pax_global_header00006660000000000000000000000064126472062630014522gustar00rootroot0000000000000052 comment=da1f4b0e62f18f5308fffb7b165b06db48608077 libmongoc-1.3.1/000077500000000000000000000000001264720626300134755ustar00rootroot00000000000000libmongoc-1.3.1/.gitattributes000066400000000000000000000000331264720626300163640ustar00rootroot00000000000000tests/binary/* text eol=lf libmongoc-1.3.1/.gitignore000066400000000000000000000021671264720626300154730ustar00rootroot00000000000000*~ *.a aclocal.m4 aggregation1 AUTHORS autom4te.cache bulk1 bulk2 bulk3 bulk4 bulk5 ChangeLog cluster1 CMakeCache.txt CMakeFiles compile config.* configure COPYING data depcomp .deps .dirstamp .DS_Store echo-server example-client example-scram example-gridfs example-matcher filter-bsondump find-and-modify fam *.gcda *.gcno *.gz index-source INSTALL install-sh *.la .libs libtool *.lo ltmain.sh Makefile Makefile.in missing mongoc-dump mongoc-ping mongoc-rpc-validate mongoc-stat mongoc-tail *.o *.pc README repltest1 shardtest1 shardtest2 *.so *.so.* stamp-h1 *.swp tags test-libmongoc test-load test.log test-mock-server test-mongoc-array test-mongoc-buffer test-mongoc-client test-mongoc-client-pool test-mongoc-collection test-mongoc-cursor test-mongoc-database test-mongoc-exhaust test-mongoc-event test-mongoc-find-and-modify test-mongoc-gridfs test-mongoc-gridfs-file-page test-mongoc-list test-mongoc-matcher test-mongoc-queue test-mongoc-read-prefs test-mongoc-rpc test-mongoc-stream test-mongoc-stream-tls test-mongoc-uri test-mongoc-write-concern test-replica-set test-replica-set-ssl test-secondary test-sharded-cluster test-x509 libmongoc-1.3.1/.gitmodules000066400000000000000000000001541264720626300156520ustar00rootroot00000000000000[submodule "src/libbson"] path = src/libbson url = https://github.com/mongodb/libbson.git ignore = dirty libmongoc-1.3.1/.mci.yml000066400000000000000000001027451264720626300150570ustar00rootroot00000000000000####################################### # C Driver Config for MCI # ####################################### ## Some variables for convenience: c_driver_variables: test_list: &std_tests - name: "compile" - name: "integration-test-latest" ## Note that the in 3.0, the default storage engine is MMAPv1 and ## WiredTiger is opt-in, but in latest as of MongoDB 3.1.4, the ## default is WiredTiger and MMAPv1 is opt-in. storage_engine_test_list: &storage_engine_tests - name: "compile" - name: "integration-test-3.0" - name: "integration-test-3.0-with-WiredTiger" - name: "integration-test-latest" - name: "integration-test-latest-with-MMAPv1" release_archive: &release_archive_builder - name: "releasearchive" topology_test_list: &topology_tests - name: "compile" - name: "integration-test-2.4" - name: "integration-test-2.4-replica-set" - name: "integration-test-2.4-sharded" - name: "integration-test-2.6" - name: "integration-test-2.6-replica-set" - name: "integration-test-2.6-sharded" - name: "integration-test-3.0" - name: "integration-test-3.0-replica-set" - name: "integration-test-3.0-sharded" - name: "integration-test-latest" - name: "integration-test-latest-replica-set" - name: "integration-test-latest-sharded" topology_test_no_auth_list: &topology_tests_no_auth - name: "compile" - name: "integration-test-2.4-no-auth" - name: "integration-test-2.4-replica-set-no-auth" - name: "integration-test-2.4-sharded-no-auth" - name: "integration-test-2.6-no-auth" - name: "integration-test-2.6-replica-set-no-auth" - name: "integration-test-2.6-sharded-no-auth" - name: "integration-test-3.0-no-auth" - name: "integration-test-3.0-replica-set-no-auth" - name: "integration-test-3.0-sharded-no-auth" - name: "integration-test-latest-no-auth" - name: "integration-test-latest-replica-set-no-auth" - name: "integration-test-latest-sharded-no-auth" ssl_test_list: &ssl_tests - name: "compile" - name: "integration-test-3.0-ssl" ## Common download urls (merge in as hashes) mongo_download_url_prefixes: linux64: &mongo_url_linux64 mongo_url_prefix: "http://downloads.mongodb.org/linux/mongodb-linux-x86_64-" ubuntu1204: &mongo_url_ubuntu1204 mongo_url_platform: "ubuntu1204-" <<: *mongo_url_linux64 ubuntu1404: &mongo_url_ubuntu1404 mongo_url_platform: "ubuntu1404-" <<: *mongo_url_linux64 windows64: &mongo_url_windows64 mongo_url_prefix: "http://downloads.mongodb.org/win32/mongodb-win32-x86_64-" mongo_url_platform: "" windows32: &mongo_url_windows32 mongo_url_prefix: "http://downloads.mongodb.org/win32/mongodb-win32-i386-" rhel55: &mongo_url_rhel55 mongo_url_platform: "rhel57-" <<: *mongo_url_linux64 rhel55_32: &mongo_url_rhel55_32 mongo_url_prefix: "http://downloads.mongodb.org/linux/mongodb-linux-i686-" osx-108: &mongo_url_osx_108 mongo_url_prefix: "http://downloads.mongodb.org/osx/mongodb-osx-x86_64-" solaris: &mongo_url_solaris mongo_url_prefix: "http://downloads.mongodb.org/sunos5/mongodb-sunos5-x86_64-" ## Common sets of CFLAGS cflags: standard: &cflags_64 cflags: "-m64 -march=x86-64 -Werror" standard_32: &cflags_32 cflags: "-m32 -march=i386 -Werror" osx_108: &cflags_osx_108 cflags: "-m64 -march=x86-64" solaris_64: &cflags_solaris_64 cflags: "-m64 -march=x86-64" ## Extra $PATH entries paths: unix_path: &unix_path extra_path: osx_path: &osx_path extra_path: windows_path: &windows_path extra_path: /cygdrive/c/mongo-c-driver/bin:/cygdrive/c/openssl/bin solaris_path: &solaris_path extra_path: /opt/mongodbtoolchain/bin ## Scripts that are shared between buildvariants scripts: mongo_orchestration: windows: &mongo_orchestration_windows start_mongo_orchestration: | trap 'set +o errexit; cat server.log; mongo-orchestration --pidfile c:\\mo.pid stop;' EXIT pidfile=/cygdrive/c/mo.pid if [ -f $pidfile ]; then echo "Existing pidfile $pidfile" cat $pidfile mongo-orchestration --pidfile c:\\mo.pid stop rm -f $pidfile fi ls -la fsutil volume diskfree c: echo "Starting Mongo Orchestration..." echo "{ \"releases\": { \"default\": \"c:\\\\mongodb\\\\bin\" }}" > orchestration.config mongo-orchestration -f orchestration.config -e default -s wsgiref start --socket-timeout-ms=60000 --bind=127.0.0.1 --enable-majority-read-concern --pidfile c:\\mo.pid sleep 10 cat c:\\mo.pid cat orchestration.config cat server.log curl -s http://localhost:8889/ unix: &mongo_orchestration_unix start_mongo_orchestration: | trap 'set +o errexit; cat server.log; mongo-orchestration --pidfile /data/mo.pid stop;' EXIT pidfile=/data/mo.pid if [ -f $pidfile ]; then echo "Existing pidfile $pidfile" cat $pidfile mongo-orchestration --pidfile /data/mo.pid stop; rm -f $pidfile fi df -h ls -la echo "Starting Mongo Orchestration..." echo "{ \"releases\": { \"default\": \"`pwd`/mongodb/bin\" } }" > orchestration.config TMPDIR=/data/db mongo-orchestration -f orchestration.config -e default start --socket-timeout-ms=60000 --bind=127.0.0.1 --enable-majority-read-concern --pidfile $pidfile curl -s http://localhost:8889/ start_topology_command: &start_topology_command start_topology: | curl -s --data @"$ORCHESTRATION_FILE" "$ORCHESTRATION_URL" ./mongodb/bin/mongo $MONGO_SHELL_CONNECTION_FLAGS --eval 'printjson(db.serverBuildInfo())' admin ./mongodb/bin/mongo $MONGO_SHELL_CONNECTION_FLAGS --eval 'printjson(db.adminCommand({getCmdLineOpts:1}))' admin ./mongodb/bin/mongo $MONGO_SHELL_CONNECTION_FLAGS --eval 'printjson(db.isMaster())' admin compile: unix: &compile_unix compile_script: | set -o errexit set -o verbose ./configure --enable-optimizations --enable-man-pages --enable-sasl --enable-ssl --enable-maintainer-flags --enable-debug --with-libbson=bundled make -j8 solaris64: &compile_solaris64 compile_script: | set -o errexit set -o verbose sudo /opt/csw/bin/pkgutil -y -i sasl_dev export SASL_CFLAGS="-I/opt/csw/include/" export SASL_LIBS="-L/opt/csw/lib/amd64/ -lsasl2" ./configure --enable-optimizations --enable-man-pages --enable-sasl --enable-ssl --enable-maintainer-flags --enable-debug --with-libbson=bundled make solaris: &compile_solaris compile_script: | set -o errexit set -o verbose ./configure --enable-optimizations --enable-man-pages --enable-sasl --enable-ssl --enable-maintainer-flags --enable-debug --with-libbson=bundled make msvc: &compile_msvc compile_script: | file "tests/binary/gridfs-large.dat" set -o errexit set -o verbose cmake="/cygdrive/c/cmake/bin/cmake" dumpbin="/cygdrive/c/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin/dumpbin.exe" cd src/libbson echo "GENERATOR: $GENERATOR, CMAKE_DEFS: $CMAKE_DEFS" "$cmake" -G "$GENERATOR" "-DCMAKE_INSTALL_PREFIX=C:/mongo-c-driver" "$MSBUILD" /m ALL_BUILD.vcxproj "$dumpbin" /HEADERS Debug/libbson-1.0.dll | head -n 25 "$MSBUILD" /m INSTALL.vcxproj cd ../.. "$cmake" -G "$GENERATOR" "-DCMAKE_INSTALL_PREFIX=C:/mongo-c-driver" "-DBSON_ROOT_DIR=C:/mongo-c-driver" $CMAKE_DEFS "$MSBUILD" /m ALL_BUILD.vcxproj "$dumpbin" /HEADERS Debug/mongoc-1.0.lib | head -n 25 "$MSBUILD" /m INSTALL.vcxproj username_password: common: &username_password_common set_username_password: | export MONGOC_TEST_USER=bob export MONGOC_TEST_PASSWORD=pwd123 export MONGO_SHELL_CONNECTION_FLAGS="-ubob -ppwd123" connection_flags: ssl: &connection_flags_ssl set_connection_flags: | export MONGO_SHELL_CONNECTION_FLAGS="$MONGO_SHELL_CONNECTION_FLAGS --ssl --sslCAFile=/tmp/mongoc-test-certificates/ca.pem" export MONGOC_TEST_SSL_WEAK_CERT_VALIDATION=on export MONGOC_TEST_SSL_PEM_FILE=/tmp/mongoc-test-certificates/client.pem export MONGOC_TEST_SSL_CA_FILE=/tmp/mongoc-test-certificates/ca.pem integration_tests: msvc: &run_integration_tests_msvc run_integration_tests: | export PATH=$PATH:`pwd`/tests ./tests/make_ca.pl tests/trust_dir tests/trust_dir.cnf touch tests/trust_dir/done export PATH=$PATH:`pwd`/Debug:`pwd`/src/libbson/Debug export MONGOC_TEST_FUTURE_TIMEOUT_MS=30000 export MONGOC_ENABLE_MAJORITY_READ_CONCERN=on ./Debug/test-libmongoc.exe -d -f -p solaris: &run_integration_tests_solaris run_integration_tests: | export MONGOC_TEST_FUTURE_TIMEOUT_MS=30000 export MONGOC_ENABLE_MAJORITY_READ_CONCERN=on sudo /opt/csw/bin/pkgutil -y -i sasl_dev export SASL_CFLAGS="-I/opt/csw/include/" export SASL_LIBS="-L/opt/csw/lib/amd64/ -lsasl2" export LD_LIBRARY_PATH="/opt/csw/lib/amd64/" make TEST_ARGS="-f -p -d" check unix: &run_integration_tests_unix run_integration_tests: | export MONGOC_TEST_FUTURE_TIMEOUT_MS=30000 export MONGOC_ENABLE_MAJORITY_READ_CONCERN=on make TEST_ARGS="-f -p -d" check ## Other OS-specific attributes, grouped by OS unix_common: &unix_common <<: *username_password_common <<: *compile_unix <<: *mongo_orchestration_unix <<: *run_integration_tests_unix <<: *start_topology_command <<: *unix_path osx_common: &osx_common <<: *unix_common <<: *osx_path solaris_common: &solaris_common <<: *unix_common <<: *compile_solaris <<: *solaris_path solaris64_common: &solaris64_common <<: *username_password_common <<: *compile_unix <<: *mongo_orchestration_unix <<: *run_integration_tests_solaris <<: *start_topology_command <<: *unix_path <<: *compile_solaris64 <<: *solaris_path ssl: &ssl <<: *connection_flags_ssl ## Misc. for Windows builds windows_compilers: msvc2010_32bit: &with_msvc2010_32bit generator: Visual Studio 10 2010 # Evergreen builders only have 64-bit SSL and SASL available. cmake_defs: "-DENABLE_SSL:BOOL=OFF -DENABLE_SASL:BOOL=OFF" msbuild: /cygdrive/c/Windows/Microsoft.NET/Framework/v4.0.30319/MSBuild.exe msvc2010: &with_msvc2010 <<: *username_password_common generator: Visual Studio 10 2010 Win64 msbuild: /cygdrive/c/Windows/Microsoft.NET/Framework64/v4.0.30319/MSBuild.exe dllpath: "c:/openssl/bin,c:/sasl/bin" msvc2013_32bit: &with_msvc2013_32bit generator: Visual Studio 12 2013 # Evergreen builders only have 64-bit SSL and SASL available. cmake_defs: "-DENABLE_SSL:BOOL=OFF -DENABLE_SASL:BOOL=OFF" msbuild: /cygdrive/c/Program Files (x86)/MSBuild/12.0/Bin/MSBuild.exe msvc2013: &with_msvc2013 <<: *username_password_common generator: Visual Studio 12 2013 Win64 msbuild: /cygdrive/c/Program Files (x86)/MSBuild/12.0/Bin/MSBuild.exe dllpath: "c:/openssl/bin,c:/sasl/bin" msvc2015_32bit: &with_msvc2015_32bit generator: Visual Studio 14 2015 # Evergreen builders only have 64-bit SSL and SASL available. cmake_defs: "-DENABLE_SSL:BOOL=OFF -DENABLE_SASL:BOOL=OFF" msbuild: /cygdrive/c/Program Files (x86)/MSBuild/14.0/Bin/MSBuild.exe msvc2015: &with_msvc2015 <<: *username_password_common generator: Visual Studio 14 2015 Win64 msbuild: /cygdrive/c/Program Files (x86)/MSBuild/14.0/Bin/MSBuild.exe dllpath: "c:/openssl/bin,c:/sasl/bin" ## all windows buildvariants have these attributes in common windows_common: &windows_common mongo_url_extension: "zip" extension: ".exe" windows: true <<: *windows_path <<: *mongo_orchestration_windows <<: *start_topology_command msvc_common: &msvc_common <<: *windows_common <<: *compile_msvc <<: *run_integration_tests_msvc ####################################### # Functions # ####################################### functions: "fetch releasearchive" : command: shell.exec params: script: | set -o verbose set -o errexit rm -rf mongo-c-driver* ls -la curl -s https://s3.amazonaws.com/mciuploads/mongo-c-driver/${revision}/${version_id}/artifacts/mongo-c-driver-archive.tar.gz --output mongo-c-driver-archive.tar.gz tar zxvf mongo-c-driver-archive.tar.gz rm mongo-c-driver-archive.tar.gz mv mongo-c-driver* mongo-c-driver "fetch source" : command: git.get_project params: directory: mongo-c-driver "fetch mongodb" : command: shell.exec params: working_dir: "mongo-c-driver" script: | set -o verbose set -o errexit ls -la curl -s ${mongo_url} --output mongo-archive.${ext|tgz} ${decompress} mongo-archive.${ext|tgz} mv mongodb* mongodb chmod +x ./mongodb/bin/mongod${extension} if [ ${windows|false} = true ]; then rm -rf /cygdrive/c/mongodb cp -r mongodb /cygdrive/c/mongodb fi "create working directory" : command: shell.exec params: script: | rm -rf mongo-c-driver mkdir mongo-c-driver # MCI's S3 mechanism doesn't support symlinks, use curl instead of s3.get "fetch artifacts" : command: shell.exec params: working_dir: "mongo-c-driver" script: | set -o verbose set -o errexit ls -la curl http://s3.amazonaws.com/mciuploads/mongo-c-driver/${build_variant}/${revision}/artifacts/mongo-${build_id}.tar.gz -o ${build_id}.tar.gz --silent --max-time 120 tar -xzf ${build_id}.tar.gz "compile function" : command: shell.exec params: working_dir: "mongo-c-driver" script: | export PATH=${extra_path}:$PATH export GENERATOR="${generator}" # For CMake on Windows export MSBUILD="${msbuild}" # For CMake on Windows export CMAKE_DEFS="${cmake_defs}" # For CMake on Windows export CFLAGS="${cflags}" ${compile_script} "set topology standalone" : command: expansions.update params: updates: - key: "orchestration_file" value: "auth.json" - key: "topology_type" value: "server" "set-topology-standalone-ssl" : command: expansions.update params: updates: - key: "orchestration_file" value: "ssl.json" - key: "topology_type" value: "server" "set topology replica set" : command: expansions.update params: updates: - key: "orchestration_file" value: "auth.json" - key: "topology_type" value: "replica_set" "set topology sharded" : command: expansions.update params: updates: - key: "orchestration_file" value: "auth.json" - key: "topology_type" value: "sharded_cluster" "set topology standalone no auth" : command: expansions.update params: updates: - key: "orchestration_file" value: "basic.json" - key: "topology_type" value: "server" "set topology replica set no auth" : command: expansions.update params: updates: - key: "orchestration_file" value: "basic.json" - key: "topology_type" value: "replica_set" "set topology sharded no auth" : command: expansions.update params: updates: - key: "orchestration_file" value: "basic.json" - key: "topology_type" value: "sharded_cluster" "use WiredTiger storage" : command: expansions.update params: updates: - key: "orchestration_file" value: "wiredtiger.json" - key: "topology_type" value: "server" "use MMAPv1 storage" : command: expansions.update params: updates: - key: "orchestration_file" value: "mmapv1.json" - key: "topology_type" value: "server" "set version 2.4" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}2.4.14.${mongo_url_extension|tgz} "set version 2.6" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}2.6.10.${mongo_url_extension|tgz} "set version 3.0" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}${mongo_url_platform|}3.0.5.${mongo_url_extension|tgz} "set version latest" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}${mongo_url_platform|}latest.${mongo_url_extension|tgz} "copy certificates" : command: shell.exec params: working_dir: "mongo-c-driver" script: | set -o errexit set -o verbose # TODO: this won't work for Windows cp -rf orchestration_configs/certificates /tmp/mongoc-test-certificates "run integration tests" : command: shell.exec params: working_dir: "mongo-c-driver" script: | set -o errexit set -o verbose export ORCHESTRATION_FILE="orchestration_configs/${topology_type}s/${orchestration_file}" export ORCHESTRATION_URL="http://localhost:8889/v1/${topology_type}s" ${set_username_password} ${set_connection_flags} ${start_mongo_orchestration} ${start_topology} ${run_integration_tests} ####################################### # Pre Task # ####################################### pre: - command: shell.track post: - command: shell.exec params: working_dir: "mongo-c-driver" script: | if [ ${windows|false} = true ]; then mongo-orchestration --pidfile c:\\mo.pid stop rm -f /cygdrive/c/mo.pid else mongo-orchestration --pidfile /data/mo.pid stop rm -f /data/mo.pid fi pkill -9 mongo-orchestration; pkill -9 mongod; pkill -9 mongos; rm -rf /tmp/mongo* /data/db cat server.log - command: shell.cleanup ####################################### # Tasks # ####################################### tasks: - name: releasearchive commands: - func: "fetch source" - command: git.apply_patch params: directory: "mongo-c-driver" - command: shell.exec params: working_dir: "mongo-c-driver" script: | set -o errexit set -o verbose sudo apt-get update sudo apt-get install -y yelp-tools yelp-xsl ./autogen.sh --enable-man-pages --enable-html-docs --enable-sasl --enable-ssl --enable-maintainer-flags --enable-debug --with-libbson=bundled make dist mv mongo-c-driver*.tar.gz ../mongo-c-driver-archive.tar.gz ls -la - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: mongo-c-driver-archive.tar.gz remote_file: mongo-c-driver/${revision}/${version_id}/artifacts/mongo-c-driver-archive.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} - name: compile depends_on: - name: "releasearchive" variant: ubuntu-1404-64-release commands: - func: "fetch releasearchive" - func: "compile function" - command: shell.exec params: working_dir: "mongo-c-driver" script: | set -o errexit set -o verbose tar -czf ../mongo-c-driver.tar.gz . - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: mongo-c-driver.tar.gz remote_file: mongo-c-driver/${build_variant}/${revision}/artifacts/mongo-${build_id}.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} - name: "integration-test-2.4" depends_on: - name: "compile" commands: - func: "set topology standalone" - func: "set version 2.4" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.4-replica-set" depends_on: - name: "compile" commands: - func: "set topology replica set" - func: "set version 2.4" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.4-sharded" depends_on: - name: "compile" commands: - func: "set topology sharded" - func: "set version 2.4" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.6" depends_on: - name: "compile" commands: - func: "set topology standalone" - func: "set version 2.6" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.6-replica-set" depends_on: - name: "compile" commands: - func: "set topology replica set" - func: "set version 2.6" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.6-sharded" depends_on: - name: "compile" commands: - func: "set topology sharded" - func: "set version 2.6" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0" depends_on: - name: "compile" commands: - func: "set topology standalone" - func: "set version 3.0" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0-replica-set" depends_on: - name: "compile" commands: - func: "set topology replica set" - func: "set version 3.0" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0-sharded" depends_on: - name: "compile" commands: - func: "set topology sharded" - func: "set version 3.0" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-latest" depends_on: - name: "compile" commands: - func: "set topology standalone" - func: "set version latest" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-latest-replica-set" depends_on: - name: "compile" commands: - func: "set topology replica set" - func: "set version latest" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-latest-sharded" depends_on: - name: "compile" commands: - func: "set topology sharded" - func: "set version latest" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.4-no-auth" depends_on: - name: "compile" commands: - func: "set topology standalone no auth" - func: "set version 2.4" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.4-replica-set-no-auth" depends_on: - name: "compile" commands: - func: "set topology replica set no auth" - func: "set version 2.4" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.4-sharded-no-auth" depends_on: - name: "compile" commands: - func: "set topology sharded no auth" - func: "set version 2.4" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.6-no-auth" depends_on: - name: "compile" commands: - func: "set topology standalone no auth" - func: "set version 2.6" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.6-replica-set-no-auth" depends_on: - name: "compile" commands: - func: "set topology replica set no auth" - func: "set version 2.6" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.6-sharded-no-auth" depends_on: - name: "compile" commands: - func: "set topology sharded no auth" - func: "set version 2.6" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0-no-auth" depends_on: - name: "compile" commands: - func: "set topology standalone no auth" - func: "set version 3.0" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0-replica-set-no-auth" depends_on: - name: "compile" commands: - func: "set topology replica set no auth" - func: "set version 3.0" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0-sharded-no-auth" depends_on: - name: "compile" commands: - func: "set topology sharded no auth" - func: "set version 3.0" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-latest-no-auth" depends_on: - name: "compile" commands: - func: "set topology standalone no auth" - func: "set version latest" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-latest-replica-set-no-auth" depends_on: - name: "compile" commands: - func: "set topology replica set no auth" - func: "set version latest" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-latest-sharded-no-auth" depends_on: - name: "compile" commands: - func: "set topology sharded no auth" - func: "set version latest" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-latest-with-MMAPv1" depends_on: - name: "compile" commands: - func: "set topology standalone" - func: "set version latest" - func: "use MMAPv1 storage" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0-with-WiredTiger" depends_on: - name: "compile" commands: - func: "set topology standalone" - func: "set version 3.0" - func: "use WiredTiger storage" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0-ssl" depends_on: - name: "compile" commands: - func: "set-topology-standalone-ssl" - func: "set version 3.0" - func: "create working directory" - func: "fetch artifacts" - func: "fetch mongodb" - func: "copy certificates" - func: "run integration tests" ####################################### # Buildvariants # ####################################### buildvariants: ####################################### # Linux Buildvariants # ####################################### ### RHEL 5.5 # #- name: rhel55 # display_name: "RHEL 5.5" # expansions: # <<: *cflags_64 # <<: *warning_flags_rhel55 # <<: *cpppath_rhel55 # <<: *libpath_rhel55_64 # <<: *mongo_url_rhel55 # run_on: # - rhel55-test # tasks: *topology_tests # ### RHEL 5.5 32-bit # #- name: rhel55-32-bit # display_name: "RHEL 5.5 32" # expansions: # <<: *cflags_32 # <<: *warning_flags_rhel55 # <<: *cpppath_rhel55 # <<: *libpath_rhel55_32 # <<: *mongo_url_rhel55_32 # run_on: # - rhel55-test # tasks: *topology_tests - name: ubuntu-1404-64-release display_name: "Release Archive Creator" expansions: <<: *cflags_64 <<: *mongo_url_ubuntu1404 <<: *unix_common run_on: - ubuntu1404-build tasks: *release_archive_builder ## Ubuntu 1204 - name: ubuntu-1204-64 display_name: "Ubu 12 gcc-4.6.3 64" expansions: <<: *cflags_64 <<: *mongo_url_ubuntu1204 <<: *unix_common run_on: - ubuntu1204-test tasks: *topology_tests ## Ubuntu 1404 - name: ubuntu-1404-64 display_name: "Ubu 14 gcc-4.8.4 64" expansions: <<: *cflags_64 <<: *mongo_url_ubuntu1404 <<: *unix_common run_on: - ubuntu1404-test tasks: *topology_tests ## Ubuntu 1404 - name: ubuntu-1404-64-ssl display_name: "Ubu 14 gcc-4.8.4 64 SSL" expansions: <<: *cflags_64 <<: *mongo_url_ubuntu1404 <<: *unix_common <<: *ssl run_on: - ubuntu1404-test tasks: *ssl_tests ####################################### # OS X Buildvariants # ####################################### - name: os-x-108-64 display_name: "OSX 10.8 clang 64" expansions: <<: *mongo_url_osx_108 <<: *cflags_osx_108 <<: *osx_common run_on: - osx-108 tasks: *topology_tests ####################################### # Windows Buildvariants # ####################################### - name: windows-32-vs2010 display_name: "Win VS2010 32" expansions: <<: *msvc_common <<: *mongo_url_windows64 <<: *with_msvc2010_32bit run_on: - windows-64-vs2010-compile tasks: *topology_tests_no_auth - name: windows-64-vs2010 display_name: "Win VS2010 64" expansions: <<: *msvc_common <<: *mongo_url_windows64 <<: *with_msvc2010 run_on: - windows-64-vs2010-compile tasks: *topology_tests - name: windows-32-vs2013 display_name: "Win VS2013 32" expansions: <<: *msvc_common <<: *mongo_url_windows64 <<: *with_msvc2013_32bit run_on: - windows-64-vs2013-compile tasks: *topology_tests_no_auth - name: windows-64-vs2013 display_name: "Win VS2013 64" expansions: <<: *msvc_common <<: *mongo_url_windows64 <<: *with_msvc2013 run_on: - windows-64-vs2013-compile tasks: *topology_tests - name: windows-32-vs2015 display_name: "Win VS2015 32" expansions: <<: *msvc_common <<: *mongo_url_windows64 <<: *with_msvc2015_32bit run_on: - windows-64-vs2015-compile-spawn tasks: *topology_tests_no_auth - name: windows-64-vs2015 display_name: "Win VS2015 64" expansions: <<: *msvc_common <<: *mongo_url_windows64 <<: *with_msvc2015 run_on: - windows-64-vs2015-compile-spawn tasks: *topology_tests ####################################### # Solaris Buildvariant # ####################################### - name: solaris-32-bit display_name: "Sol gcc-4.8.2 32" expansions: <<: *solaris_common <<: *cflags_32 <<: *mongo_url_solaris run_on: - solaris tasks: *topology_tests - name: solaris-64-bit display_name: "Sol gcc-4.8.2 64" expansions: <<: *solaris64_common <<: *cflags_solaris_64 <<: *mongo_url_solaris run_on: - solaris tasks: *topology_tests libmongoc-1.3.1/CMakeLists.txt000066400000000000000000000352661264720626300162510ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) project (libmongoc) option(ENABLE_SSL "Use OpenSSL for TLS connections and SCRAM-SHA-1 authentication.\ NOTE: OpenSSL is required for authenticating to MongoDB 3.0 and later." ON) option(ENABLE_SASL "Use Cyrus SASL library for Kerberos." ON) option(ENABLE_TESTS "Build MongoDB C Driver tests." ON) option(ENABLE_EXAMPLES "Build MongoDB C Driver examples." ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/build/cmake) include(InstallRequiredSystemLibraries) include(FindBSON REQUIRED) if (ENABLE_SSL) include(FindOpenSSL) endif () if (ENABLE_SSL AND OPENSSL_FOUND) set (MONGOC_ENABLE_SSL 1) else () set (MONGOC_ENABLE_SSL 0) endif () if (ENABLE_SASL) include(FindSASL2) endif () if (ENABLE_SASL AND SASL2_FOUND) set (MONGOC_ENABLE_SASL 1) else () set (MONGOC_HAVE_SASL_CLIENT_DONE 0) set (MONGOC_ENABLE_SASL 0) endif () set (SOURCE_DIR "${PROJECT_SOURCE_DIR}/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/build/cmake) # Set MONGOC_MAJOR_VERSION, MONGOC_MINOR_VERSION, etc. include(LoadVersion) LoadVersion(${PROJECT_SOURCE_DIR}/VERSION_CURRENT MONGOC) LoadVersion(${PROJECT_SOURCE_DIR}/VERSION_RELEASED MONGOC_RELEASED) message("Current version (from VERSION_CURRENT file): ${MONGOC_VERSION}") if (NOT ${MONGOC_VERSION} STREQUAL ${MONGOC_RELEASED_VERSION}) message("Previous release (from VERSION_RELEASED file): ${MONGOC_RELEASED_VERSION}") endif() set (SOURCE_DIR "${PROJECT_SOURCE_DIR}/") set (MONGOC_API_VERSION 1.0) set (CPACK_RESOURCE_FILE_LICENSE "${SOURCE_DIR}/COPYING") set (CPACK_PACKAGE_VERSION_MAJOR ${MONGOC_MAJOR_VERSION}) set (CPACK_PACKAGE_VERSION_MINOR ${MONGOC_MINOR_VERSION}) include (CPack) set (MONGOC_HAVE_WEAK_SYMBOLS 0) configure_file ( "${SOURCE_DIR}/src/mongoc/mongoc-config.h.in" "${PROJECT_BINARY_DIR}/src/mongoc/mongoc-config.h" ) configure_file ( "${SOURCE_DIR}/src/mongoc/mongoc-version.h.in" "${PROJECT_BINARY_DIR}/src/mongoc/mongoc-version.h" ) include_directories("${PROJECT_BINARY_DIR}/src/mongoc") include_directories("${SOURCE_DIR}/src/mongoc") include_directories(${BSON_INCLUDE_DIR}) set(LIBS ${LIBS} ${BSON_LIBRARIES}) if (UNIX AND NOT APPLE) set(LIBS ${LIBS} rt) endif() if (APPLE) cmake_policy(SET CMP0042 OLD) endif() add_definitions(-D_GNU_SOURCE) add_definitions(-D_BSD_SOURCE) add_definitions("-DBINARY_DIR=\"${SOURCE_DIR}/tests/binary\"") if (APPLE) # Until CDRIVER-520. add_definitions(-Wno-deprecated-declarations) endif() set (SOURCES ${SOURCE_DIR}/src/mongoc/mongoc-array.c ${SOURCE_DIR}/src/mongoc/mongoc-async.c ${SOURCE_DIR}/src/mongoc/mongoc-async-cmd.c ${SOURCE_DIR}/src/mongoc/mongoc-b64.c ${SOURCE_DIR}/src/mongoc/mongoc-buffer.c ${SOURCE_DIR}/src/mongoc/mongoc-bulk-operation.c ${SOURCE_DIR}/src/mongoc/mongoc-client.c ${SOURCE_DIR}/src/mongoc/mongoc-client-pool.c ${SOURCE_DIR}/src/mongoc/mongoc-cluster.c ${SOURCE_DIR}/src/mongoc/mongoc-collection.c ${SOURCE_DIR}/src/mongoc/mongoc-counters.c ${SOURCE_DIR}/src/mongoc/mongoc-cursor-array.c ${SOURCE_DIR}/src/mongoc/mongoc-cursor.c ${SOURCE_DIR}/src/mongoc/mongoc-cursor-array.c ${SOURCE_DIR}/src/mongoc/mongoc-cursor-cursorid.c ${SOURCE_DIR}/src/mongoc/mongoc-cursor-transform.c ${SOURCE_DIR}/src/mongoc/mongoc-database.c ${SOURCE_DIR}/src/mongoc/mongoc-find-and-modify.c ${SOURCE_DIR}/src/mongoc/mongoc-init.c ${SOURCE_DIR}/src/mongoc/mongoc-gridfs.c ${SOURCE_DIR}/src/mongoc/mongoc-gridfs-file.c ${SOURCE_DIR}/src/mongoc/mongoc-gridfs-file-list.c ${SOURCE_DIR}/src/mongoc/mongoc-gridfs-file-page.c ${SOURCE_DIR}/src/mongoc/mongoc-gridfs-file-list.c ${SOURCE_DIR}/src/mongoc/mongoc-host-list.c ${SOURCE_DIR}/src/mongoc/mongoc-index.c ${SOURCE_DIR}/src/mongoc/mongoc-init.c ${SOURCE_DIR}/src/mongoc/mongoc-list.c ${SOURCE_DIR}/src/mongoc/mongoc-log.c ${SOURCE_DIR}/src/mongoc/mongoc-matcher.c ${SOURCE_DIR}/src/mongoc/mongoc-matcher-op.c ${SOURCE_DIR}/src/mongoc/mongoc-memcmp.c ${SOURCE_DIR}/src/mongoc/mongoc-opcode.c ${SOURCE_DIR}/src/mongoc/mongoc-queue.c ${SOURCE_DIR}/src/mongoc/mongoc-read-concern.c ${SOURCE_DIR}/src/mongoc/mongoc-read-prefs.c ${SOURCE_DIR}/src/mongoc/mongoc-rpc.c ${SOURCE_DIR}/src/mongoc/mongoc-server-description.c ${SOURCE_DIR}/src/mongoc/mongoc-server-stream.c ${SOURCE_DIR}/src/mongoc/mongoc-set.c ${SOURCE_DIR}/src/mongoc/mongoc-socket.c ${SOURCE_DIR}/src/mongoc/mongoc-stream-buffered.c ${SOURCE_DIR}/src/mongoc/mongoc-stream.c ${SOURCE_DIR}/src/mongoc/mongoc-stream-buffered.c ${SOURCE_DIR}/src/mongoc/mongoc-stream-file.c ${SOURCE_DIR}/src/mongoc/mongoc-stream-gridfs.c ${SOURCE_DIR}/src/mongoc/mongoc-stream-socket.c ${SOURCE_DIR}/src/mongoc/mongoc-topology.c ${SOURCE_DIR}/src/mongoc/mongoc-topology-description.c ${SOURCE_DIR}/src/mongoc/mongoc-topology-scanner.c ${SOURCE_DIR}/src/mongoc/mongoc-uri.c ${SOURCE_DIR}/src/mongoc/mongoc-util.c ${SOURCE_DIR}/src/mongoc/mongoc-version-functions.c ${SOURCE_DIR}/src/mongoc/mongoc-write-command.c ${SOURCE_DIR}/src/mongoc/mongoc-write-concern.c ) set (HEADERS ${PROJECT_BINARY_DIR}/src/mongoc/mongoc-config.h ${PROJECT_BINARY_DIR}/src/mongoc/mongoc-version.h ${SOURCE_DIR}/src/mongoc/mongoc.h ${SOURCE_DIR}/src/mongoc/mongoc-bulk-operation.h ${SOURCE_DIR}/src/mongoc/mongoc-client.h ${SOURCE_DIR}/src/mongoc/mongoc-client-pool.h ${SOURCE_DIR}/src/mongoc/mongoc-collection.h ${SOURCE_DIR}/src/mongoc/mongoc-cursor.h ${SOURCE_DIR}/src/mongoc/mongoc-database.h ${SOURCE_DIR}/src/mongoc/mongoc-error.h ${SOURCE_DIR}/src/mongoc/mongoc-flags.h ${SOURCE_DIR}/src/mongoc/mongoc-find-and-modify.h ${SOURCE_DIR}/src/mongoc/mongoc-gridfs.h ${SOURCE_DIR}/src/mongoc/mongoc-gridfs-file.h ${SOURCE_DIR}/src/mongoc/mongoc-gridfs-file-page.h ${SOURCE_DIR}/src/mongoc/mongoc-gridfs-file-list.h ${SOURCE_DIR}/src/mongoc/mongoc-host-list.h ${SOURCE_DIR}/src/mongoc/mongoc-init.h ${SOURCE_DIR}/src/mongoc/mongoc-index.h ${SOURCE_DIR}/src/mongoc/mongoc-iovec.h ${SOURCE_DIR}/src/mongoc/mongoc-log.h ${SOURCE_DIR}/src/mongoc/mongoc-matcher.h ${SOURCE_DIR}/src/mongoc/mongoc-opcode.h ${SOURCE_DIR}/src/mongoc/mongoc-opcode-private.h ${SOURCE_DIR}/src/mongoc/mongoc-read-concern.h ${SOURCE_DIR}/src/mongoc/mongoc-read-prefs.h ${SOURCE_DIR}/src/mongoc/mongoc-server-description.h ${SOURCE_DIR}/src/mongoc/mongoc-socket.h ${SOURCE_DIR}/src/mongoc/mongoc-socket-private.h ${SOURCE_DIR}/src/mongoc/mongoc-stream.h ${SOURCE_DIR}/src/mongoc/mongoc-stream-buffered.h ${SOURCE_DIR}/src/mongoc/mongoc-stream-file.h ${SOURCE_DIR}/src/mongoc/mongoc-stream-gridfs.h ${SOURCE_DIR}/src/mongoc/mongoc-stream-socket.h ${SOURCE_DIR}/src/mongoc/mongoc-uri.h ${SOURCE_DIR}/src/mongoc/mongoc-version-functions.h ${SOURCE_DIR}/src/mongoc/mongoc-write-concern.h ) if (OPENSSL_FOUND) set (HEADERS ${HEADERS} ${SOURCE_DIR}/src/mongoc/mongoc-rand.h ${SOURCE_DIR}/src/mongoc/mongoc-stream-tls.h ${SOURCE_DIR}/src/mongoc/mongoc-ssl.h) set (SOURCES ${SOURCES} ${SOURCE_DIR}/src/mongoc/mongoc-rand.c ${SOURCE_DIR}/src/mongoc/mongoc-scram.c ${SOURCE_DIR}/src/mongoc/mongoc-stream-tls.c ${SOURCE_DIR}/src/mongoc/mongoc-ssl.c ) set(LIBS ${LIBS} ${OPENSSL_LIBRARIES}) include_directories(${OPENSSL_INCLUDE_DIR}) endif() if (MONGOC_ENABLE_SASL) set (HEADERS ${HEADERS} ${SOURCE_DIR}/src/mongoc/mongoc-sasl-private.h) set (SOURCES ${SOURCES} ${SOURCE_DIR}/src/mongoc/mongoc-sasl.c) set(LIBS ${LIBS} ${SASL2_LIBRARY}) include_directories(${SASL2_INCLUDE_DIR}) endif() if (MSVC) if (MONGOC_ENABLE_SSL) set(MONGOC_SHARED_SOURCES ${SOURCES} ${PROJECT_SOURCE_DIR}/build/cmake/libmongoc-ssl.def) else () set(MONGOC_SHARED_SOURCES ${SOURCES} ${PROJECT_SOURCE_DIR}/build/cmake/libmongoc.def) endif() else() set(MONGOC_SHARED_SOURCES ${SOURCES}) endif() add_library(mongoc_shared SHARED ${MONGOC_SHARED_SOURCES} ${HEADERS}) add_library(mongoc_static STATIC ${SOURCES} ${HEADERS}) target_link_libraries(mongoc_shared ${LIBS}) target_link_libraries(mongoc_static ${LIBS}) set_target_properties(mongoc_shared PROPERTIES COMPILE_DEFINITIONS "MONGOC_COMPILATION") set_target_properties(mongoc_static PROPERTIES COMPILE_DEFINITIONS "MONGOC_COMPILATION") set_target_properties(mongoc_shared PROPERTIES VERSION ${MONGOC_VERSION} SOVERSION ${MONGOC_MAJOR_VERSION}) set_target_properties(mongoc_static PROPERTIES VERSION ${MONGOC_VERSION} SOVERSION ${MONGOC_MAJOR_VERSION}) set_target_properties(mongoc_shared PROPERTIES OUTPUT_NAME "mongoc-${MONGOC_API_VERSION}" PREFIX "lib") set_target_properties(mongoc_static PROPERTIES OUTPUT_NAME "mongoc-static-${MONGOC_API_VERSION}") function(mongoc_add_test test use_shared) if (ENABLE_TESTS) add_executable(${test} ${ARGN}) if (${use_shared}) target_link_libraries(${test} mongoc_shared) else() set_target_properties(${test} PROPERTIES COMPILE_DEFINITIONS "MONGOC_COMPILATION") target_link_libraries(${test} mongoc_static) endif() if(WIN32) target_link_libraries(${test} shlwapi) endif() endif() endfunction() function(mongoc_add_example example use_shared) if (ENABLE_EXAMPLES) add_executable(${example} ${ARGN}) if (${use_shared}) target_link_libraries(${example} mongoc_shared) else() set_target_properties(${example} PROPERTIES COMPILE_DEFINITIONS "MONGOC_COMPILATION") target_link_libraries(${example} mongoc_static) endif() if(WIN32) target_link_libraries(${example} shlwapi) endif() set (EXAMPLES ${EXAMPLES} ${example}) endif () endfunction() set(test-libmongoc-sources ${SOURCE_DIR}/tests/debug-stream.c ${SOURCE_DIR}/tests/ha-test.c ${SOURCE_DIR}/tests/json-test.c ${SOURCE_DIR}/tests/mock_server/future.c ${SOURCE_DIR}/tests/mock_server/future-functions.c ${SOURCE_DIR}/tests/mock_server/future-value.c ${SOURCE_DIR}/tests/mock_server/sync-queue.c ${SOURCE_DIR}/tests/mock_server/mock-rs.c ${SOURCE_DIR}/tests/mock_server/mock-server.c ${SOURCE_DIR}/tests/mock_server/request.c ${SOURCE_DIR}/tests/test-conveniences.c ${SOURCE_DIR}/tests/test-bulk.c ${SOURCE_DIR}/tests/test-libmongoc.c ${SOURCE_DIR}/tests/test-mongoc-array.c ${SOURCE_DIR}/tests/test-mongoc-async.c ${SOURCE_DIR}/tests/test-mongoc-buffer.c ${SOURCE_DIR}/tests/test-mongoc-client.c ${SOURCE_DIR}/tests/test-bulk.c ${SOURCE_DIR}/tests/test-mongoc-client-pool.c ${SOURCE_DIR}/tests/test-mongoc-cluster.c ${SOURCE_DIR}/tests/test-mongoc-collection.c ${SOURCE_DIR}/tests/test-mongoc-collection-find.c ${SOURCE_DIR}/tests/test-mongoc-cursor.c ${SOURCE_DIR}/tests/test-mongoc-database.c ${SOURCE_DIR}/tests/test-mongoc-exhaust.c ${SOURCE_DIR}/tests/test-mongoc-find-and-modify.c ${SOURCE_DIR}/tests/test-mongoc-gridfs.c ${SOURCE_DIR}/tests/test-mongoc-gridfs-file-page.c ${SOURCE_DIR}/tests/test-mongoc-list.c ${SOURCE_DIR}/tests/test-mongoc-log.c ${SOURCE_DIR}/tests/test-mongoc-matcher.c ${SOURCE_DIR}/tests/test-mongoc-queue.c ${SOURCE_DIR}/tests/test-mongoc-read-prefs.c ${SOURCE_DIR}/tests/test-mongoc-rpc.c ${SOURCE_DIR}/tests/test-mongoc-sdam.c ${SOURCE_DIR}/tests/test-mongoc-server-selection.c ${SOURCE_DIR}/tests/test-mongoc-server-selection-errors.c ${SOURCE_DIR}/tests/test-mongoc-set.c ${SOURCE_DIR}/tests/test-mongoc-socket.c ${SOURCE_DIR}/tests/test-mongoc-stream.c ${SOURCE_DIR}/tests/test-mongoc-thread.c ${SOURCE_DIR}/tests/test-mongoc-topology.c ${SOURCE_DIR}/tests/test-mongoc-topology-reconcile.c ${SOURCE_DIR}/tests/test-mongoc-topology-scanner.c ${SOURCE_DIR}/tests/test-mongoc-uri.c ${SOURCE_DIR}/tests/test-mongoc-version.c ${SOURCE_DIR}/tests/test-mongoc-usleep.c ${SOURCE_DIR}/tests/test-mongoc-write-concern.c ${SOURCE_DIR}/tests/test-sasl.c ${SOURCE_DIR}/tests/test-write-commands.c ${SOURCE_DIR}/tests/TestSuite.c ) if (MONGOC_ENABLE_SSL) set(test-libmongoc-sources ${test-libmongoc-sources} ${SOURCE_DIR}/tests/test-x509.c ${SOURCE_DIR}/tests/ssl-test.c ${SOURCE_DIR}/tests/test-mongoc-stream-tls.c ${SOURCE_DIR}/tests/test-mongoc-stream-tls-error.c) mongoc_add_test(test-replica-set-ssl FALSE ${SOURCE_DIR}/tests/test-replica-set-ssl.c ${SOURCE_DIR}/tests/ha-test.c ${SOURCE_DIR}/tests/mongoc-tests.c ) endif() mongoc_add_test(test-load FALSE ${SOURCE_DIR}/tests/test-load.c ${SOURCE_DIR}/tests/mongoc-tests.c) mongoc_add_test(test-secondary FALSE ${SOURCE_DIR}/tests/test-secondary.c ${SOURCE_DIR}/tests/mongoc-tests.c) mongoc_add_test(test-replica-set FALSE ${SOURCE_DIR}/tests/test-replica-set.c ${SOURCE_DIR}/tests/mongoc-tests.c ${SOURCE_DIR}/tests/ha-test.c) mongoc_add_test(test-sharded-cluster FALSE ${SOURCE_DIR}/tests/test-sharded-cluster.c ${SOURCE_DIR}/tests/mongoc-tests.c ${SOURCE_DIR}/tests/ha-test.c) mongoc_add_test(test-libmongoc FALSE ${test-libmongoc-sources}) if (ENABLE_TESTS) enable_testing() add_test(NAME test-libmongoc COMMAND test-libmongoc -f -p) endif () mongoc_add_example(example-gridfs TRUE ${SOURCE_DIR}/examples/example-gridfs.c) mongoc_add_example(example-client TRUE ${SOURCE_DIR}/examples/example-client.c) mongoc_add_example(example-scram TRUE ${SOURCE_DIR}/examples/example-scram.c) mongoc_add_example(mongoc-dump TRUE ${SOURCE_DIR}/examples/mongoc-dump.c) mongoc_add_example(mongoc-ping TRUE ${SOURCE_DIR}/examples/mongoc-ping.c) mongoc_add_example(mongoc-rpc-validate FALSE ${SOURCE_DIR}/examples/mongoc-rpc-validate.c) mongoc_add_example(mongoc-tail TRUE ${SOURCE_DIR}/examples/mongoc-tail.c) file(COPY ${SOURCE_DIR}/tests/binary DESTINATION ${PROJECT_BINARY_DIR}/tests) file(COPY ${SOURCE_DIR}/tests/certificates DESTINATION ${PROJECT_BINARY_DIR}/tests) install( TARGETS mongoc_shared mongoc_static ${EXAMPLES} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin ) install( FILES ${HEADERS} DESTINATION "include/libmongoc-${MONGOC_API_VERSION}" ) # Define pkg-config files set(VERSION "${MONGOC_VERSION}") set(prefix "${CMAKE_INSTALL_PREFIX}") set(libdir "\${prefix}/lib") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/libmongoc-1.0.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libmongoc-1.0.pc @ONLY) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/libmongoc-priv.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libmongoc-priv.pc @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/libmongoc-1.0.pc ${CMAKE_CURRENT_BINARY_DIR}/libmongoc-priv.pc DESTINATION lib/pkgconfig ) if (MONGOC_ENABLE_SSL) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/libmongoc-ssl-1.0.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libmongoc-ssl-1.0.pc @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/libmongoc-ssl-1.0.pc DESTINATION lib/pkgconfig ) endif() libmongoc-1.3.1/CONTRIBUTING.md000066400000000000000000000147651264720626300157430ustar00rootroot00000000000000# Contributing to mongo-c-driver Thanks for considering contributing to the mongo-c-driver! This document intends to be a short guide to helping you contribute to the codebase. It expects a familiarity with the C programming language and writing portable software. Whenever in doubt, feel free to ask others that have contributed or look at the existing body of code. ## Guidelines The mongo-c-driver has a few guidelines that help direct the process. ### Portability mongo-c-driver is portable software. It needs to run on a multitude of operating systems and architectures. * Linux (RHEL 5 and newer) * FreeBSD (10 and newer) * Windows (Vista a newer) * Solaris x86_64/SPARC (11 and newer) * SmartOS (Solaris based) * Possibly more if users show an interest. * ARM/SPARC/x86/x86_64 ### Licensing Some of the mongo-c-driver users embed the library statically in their products. Therefore, the driver needs to be liberally licensed (as opposed to the authors usual preference of LGPL-2+). Therefore, all contributions must also be under this license. As a policy, we have chosen Apache 2.0 as the license for the project. ### Coding Style We try not to be pedantic with taking contributions that are not properly formatted, but we will likely perform a followup commit that cleans things up. The basics are, in vim: : set ts=3 sw=3 et 3 space tabs, insert spaces instead of tabs. Place a space between the function name and the parameter as such: ```c static void my_func (Param *p) my_func (p); ``` Not all of the code does this today, but it should be cleaned up at some point. Just look at the code around for more pedantic styling choices. ### Enum, Struct, Variable Naming The naming conventions for mongo-c-driver should feel very object oriented. In fact, mongo-c-driver is OOP. Those that have used the GLib library will feel right at home, as the author has spent many years contributing to that project as well. Structs are suffixed in `_t`, and underscores. ```c typedef struct _my_struct_t my_struct_t; struct _my_struct_t { int foo; }; ``` Function names should be prefixed by the type name, without the `_t`. ```c int my_struct_get_foo (my_struct_t *my); ``` Enums are also named with the `_t` suffix. ```c typedef enum { MY_FLAGS_A = 1, MY_FLAGS_B = 1 << 1, MY_FLAGS_C = 1 << 2, } my_flags_t; ``` ### Adding a new symbol This should be done rarely but there are several things that you need to do when adding a new symbol. - Add the symbol to `src/libmongoc.symbols` - Add the symbol to `build/autotools/versions.ldscript` - Add the symbol to `build/cmake/libmongoc.def` - Add the symbol to `build/cmake/libmongoc-ssl.def` - Add documentation for the new symbol in `doc/mongoc_your_new_symbol_name.page` ### Documentation We strive to document all symbols. See doc/ for documentation examples. If you add a new function, add a new .txt file describing the function so that we can generate man pages and HTML for it. ### Testing To run the entire test suite, including authentication tests, start `mongod` with auth enabled: ``` $ mongod --auth ``` In another terminal, use the `mongo` shell to create a user: ``` $ mongo --eval "db.createUser({user: 'admin', pwd: 'pass', roles: ['root']})" admin ``` To authenticate against MongoDB 3.0+ requires SCRAM-SHA-1, which in turn requires a driver built with OpenSSL: ``` $ ./configure --enable-ssl` ``` Set the user and password environment variables, then build and run the tests: ``` $ export MONGOC_TEST_USER=admin $ export MONGOC_TEST_PASSWORD=pass $ make test ``` Additional environment variables: * `MONGOC_TEST_HOST`: default `localhost`, the host running MongoDB. * `MONGOC_TEST_PORT`: default 27017, MongoDB's listening port. * `MONGOC_TEST_SERVER_VERBOSE`: set to `on` for wire protocol logging from tests that use `mock_server_t`. If you start `mongod` with SSL, set these variables to configure how `make test` connects to it: * `MONGOC_TEST_SSL`: set to `on` to connect to the server with SSL. * `MONGOC_TEST_SSL_PEM_FILE`: path to a client PEM file. * `MONGOC_TEST_SSL_PEM_PWD`: the PEM file's password. * `MONGOC_TEST_SSL_CA_FILE`: path to a certificate authority file. * `MONGOC_TEST_SSL_CA_DIR`: path to a certificate authority directory. * `MONGOC_TEST_SSL_CRL_FILE`: path to a certificate revocation list. * `MONGOC_TEST_SSL_WEAK_CERT_VALIDATION`: set to `on` to relax the client's validation of the server's certificate. The SASL / GSSAPI / Kerberos tests are skipped by default. To run them, set up a separate `mongod` with Kerberos and set its host and Kerberos principal name as environment variables: * `MONGOC_TEST_GSSAPI_HOST` * `MONGOC_TEST_GSSAPI_USER` URI-escape the username, for example write "user@realm" as "user%40realm". The user must be authorized to query `test.collection`. The SASL / GSSAPI / Kerberos tests are skipped by default. To run them, set up a separate `mongod` with Kerberos and set its host and Kerberos principal name as environment variables: * `MONGOC_TEST_GSSAPI_HOST` * `MONGOC_TEST_GSSAPI_USER` URI-escape the username, for example write "user@realm" as "user%40realm". The user must be authorized to query `test.collection`. MongoDB 3.2 adds support for readConcern, but does not enable support for read concern majority by default. mongod must be launched using `--enableMajorityReadConcern`. The test framework does not (and can't) automatically discover if this option was provided to MongoDB, so an additional variable must be set to enable these tests: * `MONGOC_ENABLE_MAJORITY_READ_CONCERN` Set this environment variable to `on` if MongoDB has enabled majority read concern. All tests should pass before submitting a patch. ## Configuring the test runner The test runner can be configured by declaring the `TEST_ARGS` environment variable. The following options can be provided: ``` -h, --help Show this help menu. -f Do not fork() before running tests. -l NAME Run test by name, e.g. "/Client/command" or "/Client/*". -p Do not run tests in parallel. -v Be verbose with logs. ``` `TEST_ARGS` is set to "-f -p" by default. To run just a specific portion of the test suite use the -l option like so: ``` $ make test TEST_ARGS="-l /server_selection/*" ``` The full list of tests is shown in the help. ## Debugging failed tests The easiest way to debug a failed tests is to use the `debug` make target: ``` $ make debug TEST_ARGS="-l /WriteConcern/bson_omits_defaults" ``` This will build all dependencies and leave you in a debugger ready to run the test. libmongoc-1.3.1/COPYING000066400000000000000000000236761264720626300145460ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS libmongoc-1.3.1/Makefile.am000066400000000000000000000034121264720626300155310ustar00rootroot00000000000000EXTRA_DIST = CLEANFILES = DISTCLEANFILES = MAINTAINERCLEANFILES = bin_PROGRAMS = lib_LTLIBRARIES = noinst_LTLIBRARIES = noinst_PROGRAMS = if WITH_LIBBSON SUBDIRS = src/libbson endif AM_CTAGSFLAGS = --fields=+l --languages=c include doc/Makefile.am if ENABLE_MAN_PAGES include doc/man/Makefile.am endif if ENABLE_HTML_DOCS include doc/html/Makefile.am endif include src/Makefile.am if ENABLE_TESTS include tests/Makefile.am endif if ENABLE_EXAMPLES include examples/Makefile.am endif # for EXTRA_DIST include build/cmake/Makefile.am ACLOCAL_AMFLAGS = -I build/autotools/m4 ${ACLOCAL_FLAGS} DISTCHECK_CONFIGURE_FLAGS = --enable-silent-rules --enable-man-pages --enable-html-docs --enable-sasl --enable-ssl --enable-maintainer-flags --enable-debug --with-libbson=bundled mongocdocdir = ${docdir} mongocdoc_DATA = \ COPYING \ NEWS \ README.rst EXTRA_DIST += $(mongocdoc_DATA) EXTRA_DIST += \ CMakeLists.txt \ CONTRIBUTING.md \ VERSION_CURRENT \ VERSION_RELEASED EXTRA_DIST += $(wildcard orchestration_configs/*/*) dist-hook: @if test -d "$(srcdir)/.git"; then \ (cd "$(srcdir)" && \ $(top_srcdir)/build/autotools/missing --run git log --stat ) > ChangeLog.tmp \ && mv -f ChangeLog.tmp $(top_distdir)/ChangeLog \ || (rm -f ChangeLog.tmp; \ echo Failed to generate ChangeLog >&2); \ else \ echo A git checkout is required to generate a ChangeLog >&2; \ fi uninstall-local: -rm -r $(mongocdocdir) dist-rpm: dist-gzip cp mongo-c-driver-$(MONGOC_VERSION).tar.gz ~/rpmbuild/SOURCES/ rpmbuild -bb build/rpm/mongo-c-driver.spec libmongoc-1.3.1/NEWS000066400000000000000000001222541264720626300142020ustar00rootroot00000000000000mongo-c-driver 1.3.1 ==================== It is my pleasure to announce MongoDB C Driver 1.3.1. This is a bugfix release: * mongoc_client_get_gridfs now copies the client's read preferences, read concern, and write concern to the newly created mongoc_gridfs_t. Before this fix, GridFS operations were always executed with the default config: data was read from the primary, with the read concern level "local", and written with write concern "acknowledged". Now, if you have configured any of these options on the mongoc_client_t, they are respected by the mongoc_gridfs_t. * CMakeLists.txt now includes and installs the pkg-config files. Thanks to everyone who contributed to this release. * A. Jesse Jiryu Davis * Hannes Magnusson * Christopher Wang * Jean-Bernard Jansen * Jeremy Mikola * Jeroen Ooms Peace, A. Jesse Jiryu Davis mongo-c-driver 1.3.0 ==================== It is my pleasure to announce to you the release of the MongoDB C Driver 1.3.0. Changes since the the release candidate 1.3.0-rc0: * Fix a cursor bug introduced on big-endian platforms in 1.3.0-beta0. * Improve documentation for mongoc_host_list_t. * Move private mongoc_host_list_t functions from public header. * Refactor the build system to declare library version in one place. All new features and changes since the previous stable release, 1.2.1: * If the driver is compiled without SSL support but a URI with "ssl=true" is passed to mongoc_client_new, mongoc_client_new_from_uri, or mongoc_client_pool_new, the function logs an error and returns NULL. Before, the driver would attempt a non-SSL connection. * mongoc_collection_find_and_modify will now apply the mongoc_collection_t's write_concern_t when talking to MongoDB 3.2. * Support for MongoDB 3.2's "readConcern" feature for queries, counts, and aggregations. The option "readConcernLevel" is now accepted in the MongoDB URI. New struct mongoc_read_concern_t, and functions operating on it: - mongoc_client_get_read_concern - mongoc_client_set_read_concern - mongoc_database_get_read_concern - mongoc_database_set_read_concern - mongoc_collection_get_read_concern - mongoc_collection_set_read_concern - mongoc_read_concern_copy - mongoc_read_concern_destroy - mongoc_read_concern_get_level - mongoc_read_concern_new - mongoc_read_concern_set_level - mongoc_uri_get_read_concern * Support for MongoDB 3.2's "bypassDocumentValidation" option for writes. * New struct mongoc_bulk_write_flags_t and related functions: - mongoc_bulk_operation_set_bypass_document_validation * New struct mongoc_find_and_modify_opts_t and related functions: - mongoc_find_and_modify_opts_new - mongoc_find_and_modify_opts_destroy - mongoc_find_and_modify_opts_set_sort - mongoc_find_and_modify_opts_set_update - mongoc_find_and_modify_opts_set_fields - mongoc_find_and_modify_opts_set_flags - mongoc_find_and_modify_opts_set_bypass_document_validation - mongoc_collection_find_and_modify_with_opts * New functions to copy database and collection handles: - mongoc_collection_copy - mongoc_database_copy * Support for MongoDB 3.2 wire protocol: use commands in place of OP_QUERY, OP_GETMORE, and OP_KILLCURSORS messages. * To explain a query plan with MongoDB 3.2, you must now call the "explain" command, instead of including the "$explain" key in a mongoc_collection_find query. See the mongoc_collection_find documentation page for details. * Configurable wait time on tailable cursors with MongoDB 3.2: - mongoc_cursor_get_max_await_time_ms - mongoc_cursor_set_max_await_time_ms * Use electionId to detect a stale replica set primary during a network split. * Disconnect from replica set members whose "me" field does not match the connection address. * The client side matching feature, mongoc_matcher_t and related functions, are deprecated and scheduled for removal in version 2.0. * New CMake options ENABLE_SSL, ENABLE_SASL, ENABLE_TESTS, and ENABLE_EXAMPLES. * Use constant-time comparison when verifying credentials. * Combine environment's CFLAGS with configure options when building. * Improved man page output and "whatis" entries. There are extensive bugfixes and improvements in GridFS since 1.2.1, including: * Handle seeking, reading, and writing past the end of a GridFS file. * If a GridFS chunk is missing, mongoc_gridfs_file_readv sets file->error to domain MONGOC_ERROR_GRIDFS and a new code MONGOC_ERROR_GRIDFS_CHUNK_MISSING. * Optimization for long seeks forward with mongoc_gridfs_file_seek. Other fixes since 1.2.1: * Memory leaks in mongoc_database_has_collection and mongoc_cursor_next. * Report writeConcern failures from findAndModify and from legacy writes. * Memory leak in mongoc_database_find_collections. * Set OP_QUERY's nToReturn from the provided limit. * Fix compiler warnings and errors, especially with Visual Studio 2015, GCC 4.8, and IBM XL C. * Bugs and typos in tutorial examples. Thanks to everyone who contributed to this release. * A. Jesse Jiryu Davis * Hannes Magnusson * Kyle Suarez * Jose Sebastian Battig * Matt Cotter * Claudio Canella * alexeyvo * Christopher Wang * Flavio Medeiros * Iago Rubio * Jeremy Mikola * Victor Leschuk * Jason Carey Peace, A. Jesse Jiryu Davis mongo-c-driver 1.3.0-rc0 ======================== It is my pleasure to announce to you the first release candidate of MongoDB C driver 1.3.0. It includes additive ABI changes and bugfixes, and support for the upcoming MongoDB 3.2. It is compatible with MongoDB 2.4 and later. New features and changes since 1.3.0-beta0: * If the driver is compiled without SSL support but a URI with "ssl=true" is passed to mongoc_client_new, mongoc_client_new_from_uri, or mongoc_client_pool_new, the function logs an error and returns NULL. Before, the driver would attempt a non-SSL connection. * New functions to copy database and collection handles: - mongoc_collection_copy - mongoc_database_copy * If a GridFS chunk is missing, mongoc_gridfs_file_readv sets file->error to domain MONGOC_ERROR_GRIDFS and a new code MONGOC_ERROR_GRIDFS_CHUNK_MISSING. * Use electionId to detect a stale replica set primary during a network split. * Disconnect from replica set members whose "me" field does not match the connection address. * The client side matching feature, mongoc_matcher_t and related functions, are deprecated and scheduled for removal in version 2.0. * New CMake options ENABLE_SSL, ENABLE_SASL, ENABLE_TESTS, and ENABLE_EXAMPLES. * The build system is refactored to declare the current version and latest release in one place. Other fixes: * Memory leaks in mongoc_database_has_collection and mongoc_cursor_next. * Report writeConcern failures from findAndModify and from legacy writes. Thanks to everyone who contributed to this release candidate. * A. Jesse Jiryu Davis * Hannes Magnusson * Matt Cotter * Claudio Canella * Victor Leschuk * Flavio Medeiros * Christopher Wang Peace, A. Jesse Jiryu Davis mongo-c-driver 1.3.0-beta0 ========================== It is my pleasure to announce to you the beta of MongoDB C driver 1.3.0. This beta includes additive ABI changes and bugfixes, and support for the upcoming MongoDB 3.2. It is compatible with MongoDB 2.4 and later. New features and changes: * mongoc_collection_find_and_modify will now apply the mongoc_collection_t's write_concern_t when talking to MongoDB 3.2. * Support for MongoDB 3.2's "readConcern" feature for queries, counts, and aggregations. The option "readConcernLevel" is now accepted in the MongoDB URI. New struct mongoc_read_concern_t, and functions operating on it: - mongoc_client_get_read_concern - mongoc_client_set_read_concern - mongoc_database_get_read_concern - mongoc_database_set_read_concern - mongoc_collection_get_read_concern - mongoc_collection_set_read_concern - mongoc_read_concern_copy - mongoc_read_concern_destroy - mongoc_read_concern_get_level - mongoc_read_concern_new - mongoc_read_concern_set_level - mongoc_uri_get_read_concern * Support for MongoDB 3.2's "bypassDocumentValidation" option for writes. * New struct mongoc_bulk_write_flags_t and related functions: - mongoc_bulk_operation_set_bypass_document_validation * New struct mongoc_find_and_modify_opts_t and related functions: - mongoc_find_and_modify_opts_new - mongoc_find_and_modify_opts_destroy - mongoc_find_and_modify_opts_set_sort - mongoc_find_and_modify_opts_set_update - mongoc_find_and_modify_opts_set_fields - mongoc_find_and_modify_opts_set_flags - mongoc_find_and_modify_opts_set_bypass_document_validation - mongoc_collection_find_and_modify_with_opts * Configurable wait time on tailable cursors with MongoDB 3.2: - mongoc_cursor_get_max_await_time_ms - mongoc_cursor_set_max_await_time_ms * Support for MongoDB 3.2 wire protocol: use commands in place of OP_QUERY, OP_GETMORE, and OP_KILLCURSORS messages. * To explain a query plan with MongoDB 3.2, you must now call the "explain" command, instead of including the "$explain" key in a mongoc_collection_find query. See the mongoc_collection_find documentation page for details. * Use constant-time comparison when verifying credentials. * Combine environment's CFLAGS with configure options when building. * Improved man page output and "whatis" entries. Extensive bugfixes and improvements in GridFS, including: * Handle seeking, reading, and writing past the end of a GridFS file. * Optimization for long seeks forward with mongoc_gridfs_file_seek. Other fixes: * Memory leak in mongoc_database_find_collections. * Set OP_QUERY's nToReturn from the provided limit. * Fix compiler warnings and errors, especially with Visual Studio 2015, GCC 4.8, and IBM XL C. * Bugs and typos in tutorial examples Thanks to everyone who contributed to this beta release. * A. Jesse Jiryu Davis * Hannes Magnusson * Kyle Suarez * Jose Sebastian Battig * Jeremy Mikola * Iago Rubio * Matt Cotter * alexeyvo Peace, A. Jesse Jiryu Davis mongo-c-driver 1.2.2 ==================== It is my pleasure to announce to you the MongoDB C driver 1.2.2. This release fixes a rare bug where the driver can direct reads to hidden secondaries unintentionally. It also includes fixes and improvements to the build system. Peace, A. Jesse Jiryu Davis mongo-c-driver 1.2.1 ==================== It is my pleasure to announce to you the MongoDB C driver 1.2.1. This release includes critical bugfixes for SSL connections with mongoc_client_pool_t, and for Unix domain socket connections. The documentation is updated for a change introduced in version 1.2.0: mongoc_client_set_ssl_opts and mongoc_client_pool_set_ssl_opts now configure the driver to require an SSL connection to the server, even if "ssl=true" is omitted from the MongoDB URI. Before, SSL options were ignored unless "ssl=true" was included in the URI. The build instructions are improved, including the steps to build with OpenSSL on OS X El Capitan. Build errors and warnings are fixed for clang in gnu99 mode and MinGW. Thanks to everyone who contributed to this version of libmongoc. * A. Jesse Jiryu Davis * Hannes Magnusson * Tamas Nagy Peace, A. Jesse Jiryu Davis mongo-c-driver 1.2.0 ==================== It is my pleasure to announce to you the MongoDB C driver 1.2.0. This is a stable release with additive ABI changes and bugfixes. It is compatible with MongoDB version 2.4 and later. The following notes summarize changes since the previous stable release, 1.1.11, including changes in the 1.2.0 betas and release candidate. This version rewrites mongoc_client_t's internals to match two important new specs for MongoDB drivers: the Server Discovery And Monitoring Spec and the Server Selection Spec. The rewritten client has many advantages: * All replica set members or mongos servers are discovered and periodically checked in parallel. The driver's performance is dramatically better and more predictable with multi-server deployments, or with a flaky network, or when some servers are slow or down. * Clients from the same mongoc_client_pool_t share a background thread that discovers and monitors all servers in parallel. * Unnecessary round trips for server checks and pings are eliminated. * Behavior is documented in the specs, and consistent with other drivers, even in complex or unusual scenarios. * The URI's "replicaSet" option is enforced: the driver now refuses to connect to a server unless it is a member of a replica set with the correct setName. * Many race conditions related to changing deployment conditions are fixed. To conform to the new specs, the client now accepts these options in the MongoDB URI; see the mongoc_uri_t documentation for details: * heartbeatFrequencyMS * serverSelectionTimeoutMS * serverSelectionTryOnce * socketCheckIntervalMS Other features: * All timeouts that can be configured in the URI now interpret 0 to mean "use the default value for this timeout". * The client's read preference can be configured in the URI with the new options "readPreference" and "readPreferenceTags"; see the mongoc_uri_t documentation. * The new mongoc_uri_get_read_prefs_t function retrieves both the read mode and tags from a mongoc_uri_t. * New accessors mongoc_gridfs_file_get_id, mongoc_client_get_default_database, and mongoc_bulk_operation_get_write_concern. * Debug tracing can be controlled at runtime with mongoc_log_trace_enable and mongoc_log_trace_disable. * Set mongoc_client_pool_t's size with mongoc_client_pool_min_size() and mongoc_client_pool_max_size(). Other changes: * Enable runtime asserts in release build. * The libbson submodule's URL now uses the recommended https://, not git:// * mongoc_client_kill_cursor is now deprecated and will be removed in 2.0. * The write concern "w=-1" is documented as obsolete. These notable bugs have been fixed since 1.1.11: * The driver now uses the server's maxWireVersion to avoid an error and extra round-trip when executing aggregations on MongoDB 2.4 and older. * Much improved reporting of network errors, unavailable servers, and authentication failure * Off-by-one error in mongoc_gridfs_file_seek with mode SEEK_END * The writeConcernErrors field of bulk results is properly formatted. * A cursor with a server "hint" sets slaveOkay and / or $readPreference. * Destroying an exhaust cursor must close its socket * "wtimeoutms" was ignored for write concerns besides "majority". * Bulk write operations might fail in mixed-version sharded clusters with some pre-2.6 mongos servers. * A variety of bugs and incorrect results in mongoc_bulk_operation_execute. * Numerous compiler warnings and build failures on various platforms. * Copious refinements to the documentation. Thanks to everyone who contributed to this version of libmongoc. * Jason Carey * Samantha Ritter * A. Jesse Jiryu Davis * Hannes Magnusson * Kyle Suarez * Jeremy Mikola * Remi Collet * Jose Sebastian Battig * Derick Rethans * Yuchen Xie * Manuel Schoenlaub * Sujan Dutta * Lloyd Zhou * rubicks * Pawel Szczurko * Yuval Hager Peace, A. Jesse Jiryu Davis mongo-c-driver 1.2.0-rc0 ======================== It is my pleasure to announce the release candidate of the MongoDB C driver 1.2.0. It includes features and bugfixes developed since 1.2.0-beta1. Notable bugs fixed: * Much improved reporting of network errors, unavailable servers, and authentication failure * Destroying an exhaust cursor must close its socket * Various bugs in server reconnection logic * mongoc_collection_aggregate returned invalid cursor after failure * Wrong error message after failed network write on Sparc * Missing JSON test files in release tarball Other changes: * Enable runtime asserts in release build. * mongoc_client_kill_cursor is now deprecated and will be removed in version 2.0. This release candidate also includes all bugfixes from 1.1.11. Version 1.2.0 final will be a stable release with additive ABI changes and bugfixes. It is compatible with MongoDB version 2.4 and later. Thanks to everyone who contributed to this version of libmongoc. * A. Jesse Jiryu Davis * Hannes Magnusson * Kyle Suarez * rubicks * Jose Sebastian Battig * Jason Carey * Remi Collet * Yuval Hager Peace, A. Jesse Jiryu Davis mongo-c-driver 1.2.0-beta1 ========================== It is my pleasure to announce the second beta release of the MongoDB C driver 1.2.0. It includes features and bugfixes developed since 1.2.0-beta. New features: * Set mongoc_client_pool_t's size with mongoc_client_pool_min_size() and mongoc_client_pool_max_size(). * The write concern "w=-1" is now documented as obsolete. * Abundant fixes and additions to the documentation, beyond those in the previous beta. Notable bugs fixed: * Crashes and races in several replica set scenarios. * The driver now uses the server's maxWireVersion to avoid an error and extra round-trip when executing aggregations on MongoDB 2.4 and older. * Fixed network error handling in multiple code paths. * connectTimeoutMS limits the time the driver can spend reconnecting to servers in single-threaded (non-pooled) mode with serverSelectionTryOnce. Version 1.2.0 final will be a stable release with additive ABI changes and bugfixes. It is compatible with MongoDB version 2.4 and later. Thanks to everyone who contributed to this version of libmongoc. * A. Jesse Jiryu Davis * Hannes Magnusson * Manuel Schoenlaub * Kyle Suarez * Remi Collet Peace, A. Jesse Jiryu Davis mongo-c-driver 1.2.0-beta ========================= It is my pleasure to announce to you the first beta release of the MongoDB C driver 1.2.0. This release is a stable release with additive ABI changes and bugfixes. It is compatible with MongoDB version 2.4 and later. Version 1.2.0 rewrites mongoc_client_t's internals to match two important new specs for MongoDB drivers: the Server Discovery And Monitoring Spec and the Server Selection Spec. The rewritten client has many advantages: * All replica set members or mongoses are discovered and periodically checked in parallel. The driver's performance is dramatically better and more predictable with multi-server deployments, or with a flaky network, or when some servers are slow or down. * Clients from the same mongoc_client_pool_t share a background thread that discovers and monitors all servers in parallel. * Unnecessary round trips for server checks and pings are eliminated. * Behavior is documented in the specs, and consistent with other drivers, even in complex or unusual scenarios. * The URI's "replicaSet" option is enforced: the driver now refuses to connect to a server unless it is a member of a replica set with the right setName. * Many race conditions related to changing deployment conditions are fixed. To conform to the new specs, the client now accepts these options in the MongoDB URI; see the mongoc_uri_t documentation for details: * heartbeatFrequencyMS * serverSelectionTimeoutMS * serverSelectionTryOnce * socketCheckIntervalMS Other features: * All timeouts that can be configured in the URI now interpret 0 to mean "use the default value for this timeout". * The client's read preference can be configured in the URI with the new options "readPreference" and "readPreferenceTags", see the mongoc_uri_t documentation. * The new mongoc_uri_get_read_prefs_t function retrieves both the read mode and tags from a mongoc_uri_t. * New accessors mongoc_gridfs_file_get_id, mongoc_client_get_default_database, and mongoc_bulk_operation_get_write_concern. * Debug tracing can be controlled at runtime with mongoc_log_trace_enable and mongoc_log_trace_disable. Notable bugs fixed: * "wtimeoutms" was ignored for write concerns besides "majority". * Bulk write operations might fail in mixed-version sharded clusters with some pre-2.6 mongos servers. * Normal operations were logged during startup and could not be silenced. * A variety of bugs and incorrect results in mongoc_bulk_operation_execute. * Numerous compiler warnings and build failures on various platforms. * Copious refinements to the documentation. Thanks to everyone who contributed to this version of libmongoc. * A. Jesse Jiryu Davis * Sujan Dutta * Jason Carey * Hannes Magnusson * Jeremy Mikola * Derick Rethans * Samantha Ritter * Yuchen Xie * Lloyd Zhou Peace, A. Jesse Jiryu Davis It is my pleasure to announce to you the MongoDB C driver 1.1.11. This is a patch release with bug fixes: * Undetected network errors when sending messages to the server * Off-by-one error in mongoc_gridfs_file_seek with mode SEEK_END * Memory leak parsing a URI that contains an invalid option * The libbson submodule's URL now uses the recommended https://, not git:// Thanks to everyone who contributed to the development of this point release for libmongoc. * A. Jesse Jiryu Davis * Hannes Magnusson * Jason Carey * Jose Sebastian Battig * rubicks Peace, A. Jesse Jiryu Davis mongo-c-driver 1.1.11 ===================== It is my pleasure to announce to you the MongoDB C driver 1.1.11. This is a patch release with bug fixes: * Undetected network errors when sending messages to the server * Off-by-one error in mongoc_gridfs_file_seek with mode SEEK_END * Memory leak parsing a URI that contains an invalid option * The libbson submodule's URL now uses the recommended https://, not git:// Thanks to everyone who contributed to the development of this point release for libmongoc. * A. Jesse Jiryu Davis * Hannes Magnusson * Jason Carey * Jose Sebastian Battig * rubicks Peace, A. Jesse Jiryu Davis mongo-c-driver 1.1.10 ===================== It is my pleasure to announce to you the MongoDB C driver 1.1.10. This is a patch release with bug fixes: * Occasional crash reconnecting to replica set. * Queries sent to recovering replica set members. * Memory leak when calling ismaster on replica set members. Thanks to everyone who contributed to the development of this point release for libmongoc. * A. Jesse Jiryu Davis * Daniil Zaitsev * Jason Carey * Jeremy Mikola Peace, A. Jesse Jiryu Davis mongo-c-driver 1.1.9 ==================== It is my pleasure to announce to you the MongoDB C driver 1.1.9. This release fixes a common crash in 1.1.8, which itself was introduced while fixing a rare crash in 1.1.7. For further details: https://jira.mongodb.org/browse/CDRIVER-721 https://jira.mongodb.org/browse/CDRIVER-695 Thanks to everyone who contributed to the development of this point release for libmongoc. Peace, A. Jesse Jiryu Davis mongo-c-driver 1.1.8 ==================== UPDATE: 1.1.8 suffered a severe new bug so I removed the release from GitHub: https://jira.mongodb.org/browse/CDRIVER-721 This is a patch release with bug fixes: * Crash freeing client after a replica set auth error. * Compile error strict C89 mode. mongo-c-driver 1.1.7 ==================== It is my pleasure to announce to you the 1.1.7 release of the MongoDB C driver. This is a patch release with bug fixes: * Thread-safe use of Cyrus SASL library. * Experimental support for building with CMake and SASL. * Faster reconnection to replica set with some hosts down. * Crash iterating a cursor after reconnecting to a replica set. * Unchecked errors decoding invalid UTF-8 in MongoDB URIs. * Fix error reporting from mongoc_client_get_database_names. Thanks to everyone who contributed to the development of this point release for libmongoc. * A. Jesse Jiryu Davis * Jason Carey * Hannes Magnusson Peace, A. Jesse Jiryu Davis mongo-c-driver 1.1.6 ==================== It is my pleasure to announce to you the 1.1.6 release of the MongoDB C driver. This is a patch release with performance enhancements and bug fixes: * mongoc_bulk_operation_execute now coalesces consecutive update operations into a single message to a MongoDB 2.6+ server, yielding huge performance gains. Same for remove operations. (Inserts were always coalesced.) * Large numbers of insert operations are now properly batched according to number of documents and total data size. * GSSAPI / Kerberos auth now works. * The driver no longer tries three times in vain to reconnect to a primary, so socketTimeoutMS and connectTimeoutMS now behave *closer* to what you expect for replica sets with down members. A full fix awaits 1.2.0. I snuck in a feature: * mongoc_matcher_t now supports basic subdocument and array matching Thanks to everyone who contributed to the development of this point release for libmongoc. * A. Jesse Jiryu Davis * Jason Carey * Kai Mast * Matt Cotter Peace, A. Jesse Jiryu Davis mongo-c-driver 1.1.5 ==================== It is my pleasure to announce to you the 1.1.5 release of the MongoDB C driver. This is a patch release with performance enhancements and bug fixes: * The fsync and j write concern flags now imply acknowledged writes * Prevent using fsync or j with conflicting w=0 write concern * Obey socket timeout consistently in TLS/SSL mode * Return an error promptly after a network hangup in TLS mode * Prevent crash using SSL in FIPS mode * Always return NULL from mongoc_database_get_collection_names on error * Fix version check for GCC 5 and future versions of Clang * Fix warnings and errors building on various platforms * Add configure flag to enable/disable shared memory performance counters * Minor docs improvements and fix links from C Driver docs to Libbson docs With this release, Libbson abandons the convention that odd-numbered patch versions indicate unstable releases. We switch to simple semantic versioning: 1.1.5 is a stable release with bug fixes since 1.1.4. During subsequent development the version will be "1.1.6-dev". Thanks to everyone who contributed to the development of this point release for libmongoc. * A. Jesse Jiryu Davis * Christian Hergert * Jason Carey * Jeremy Mikola * Jeroen Ooms * Hannes Magnusson Enjoy! -- A. Jesse Jiryu Davis mongo-c-driver 1.1.4 ==================== It is my pleasure to announce to you the 1.1.4 release of the MongoDB C driver. This release is a stable release with performance enhancements and bugfixes. Changes include: * Fixed client pool concurrency issues * Fixed some scenarios where replica sets would fail to reconnect on primary step down. * Improved write concern handling * Validate port number in URI * Various other fixes Thanks to everyone who contributed to the development of this point release for libmongoc. * Jason Carey * Andrew Clayton * A. Jesse Jiryu Davis * Jeremy Mikola Enjoy! -- Jason Carey mongo-c-driver 1.1.2 ==================== It is my pleasure to announce to you the 1.1.2 release of the MongoDB C driver. This release is a stable release with performance enhancements and bugfixes. Changes include: * Process connectTimeoutMS cast insensitively * Addition of missing trace macros * Improvement of internal error messages * Fix a segfault in OpenSSL cleanup routines * Fix for IPv66 support for replica sets * Coalesce small vectorized TLS writes * MinGW fixups * Fix for a memory leak in get_database_names() * Fixes for patching write concern through the bulk api * Fix to normalize hostnames in uri parsing * Fix for managing connections in the client pool * Various other fixes Thanks to everyone who contributed to the development of this point release for libmongoc. * Andrew Clayton * Denis Gladkikh * Hannes Magnusson * Jason Carey * Jeremy Mikola * mschoenlaub * Samantha Ritter * Tyler Brock Enjoy! -- Jason Carey mongo-c-driver 1.1.0 ==================== It is my pleasure to announce to you the 1.1.0 release of the MongoDB C driver. This release is a stable release with additive ABI changes and bugfixes. The below changes include some carried over from RC0. Changes include: * RC0 * ABI versioning for 1.1 versus 1.0 symbols * additional geo index options * authMechanismProperties in URI * fixes for OS X Yosemite * removal of replica set member limit * SCRAM-SHA-1 SASL mechanism * updated dependency on libbson 1.1 abi * validation for bulk insert * various memory leak fixes * Fixes to documentation typos * "How to Ask For Help" in the README * Removed dependency on sasl for PLAIN authentication * Use provided username, if available, for X.509 auth * Fixed WriteConcern error reporting for some writes * Check for closed sockets before attempting RPCs * Fixes for gridfs file seek * Fixes for mongoc_cursor_clone() * Fixes for unix domain socket support * Fixes for polling on win32 * Improved warnings on failure to connect * Addition of wired tiger options * Fixes for examples Additions to the ABI include: * support for extra option in count - mongoc_collection_count_with_opts * additional index options - mongoc_index_opt_geo_get_default - mongoc_index_opt_geo_init - mongoc_index_opt_wt_get_default - mongoc_index_opt_wt_init * rand interface to seed and verify the strong random number generation needed by some auth mechanisms - mongoc_rand_seed - mongoc_rand_add - mongoc_rand_status * URI additions to support more complicated auth credentials - mongoc_uri_get_credentials - mongoc_uri_get_mechanism_properties * Support for cursor returning metadata crud operations - mongoc_client_find_databases - mongoc_collection_find_indexes - mongoc_database_find_collections * Kill cursor support - mongoc_client_kill_cursor * Various get/setters on cursor - mongoc_cursor_get_batch_size - mongoc_cursor_get_id - mongoc_cursor_set_batch_size * More socket/stream options - mongoc_socket_check_closed - mongoc_socket_inet_ntop - mongoc_stream_check_closed - mongoc_stream_write Additional Notes: Existing complex index names may contain a zero instead of a type due to a bug in mongoc_collection_keys_to_index_string. As a result those indexes may be hard to drop from the driver as they have a name you would not expect. Thanks to everyone who contributed to the development of this point release for libmongoc. * Adam Midvidy * aherlihy * alexeyvo * Christian Hergert * Hannes Magnusson * Jason Carey * Jérôme Lebel * Jesse Jiryu Davis * lloydzhou * Mark Benevenuto * Paul Melnikow * Samantha Ritter * Shraya Ramani * Spencer Jackson * Spencer Jackson * Tyler Brock Enjoy! -- Jason Carey mongo-c-driver 1.1.0-rc0 ======================== It is my pleasure to announce to you the 1.1.0-rc0 release of the MongoDB C driver. This release is a release candidate with additive ABI changes and bugfixes. Changes include: * ABI versioning for 1.1 versus 1.0 symbols * additional geo index options * authMechanismProperties in URI * fixes for OS X Yosemite * removal of replica set member limit * SCRAM-SHA-1 SASL mechanism * updated dependency on libbson 1.1 abi * validation for bulk insert * various memory leak fixes Additions to the ABI include: * support for extra option in count - mongoc_collection_count_with_opts * extra index and collection info - mongoc_collection_get_index_info - mongoc_database_get_collection_info * additional geo options - mongoc_index_opt_geo_get_default - mongoc_index_opt_geo_init * rand interface to seed and verify the strong random number generation needed by some auth mechanisms - mongoc_rand_seed - mongoc_rand_add - mongoc_rand_status * URI additions to support more complicated auth credentials - mongoc_uri_get_credentials - mongoc_uri_get_mechanism_properties Additional Notes: Existing complex index names may contain a zero instead of a type due to a bug in mongoc_collection_keys_to_index_string. As a result those indexes may be hard to drop from the driver as they have a name you would not expect. Thanks to everyone who contributed to the development of this point release for libmongoc. * Adam Midvidy * aherlihy * alexeyvo * Christian Hergert * Jason Carey * Jérôme Lebel * Samantha Ritter * Spencer Jackson * Tyler Brock Enjoy! -- Jason Carey mongo-c-driver 1.0.2 ==================== It is my pleasure to announce to you the 1.0.2 release of the MongoDB C driver. This release is a minor point release with no ABI changes and mostly small bugfixes. Changes include: * A variety of fixes for read preference based node selection * Avoided inclusion of getLastError in 2.6 writeConcern * Correct handling of pass through params for collection_aggregate * Improved error reporting in socket connect * Public MONGOC_DEFAULT_CONNECTTIMEOUTMS Thanks to everyone who contributed to the development of this point release for libmongoc. * Adam Midvidy * Christian Hergert * Denis Gladkikh * Jason Carey * Jeremy Mikola * Jérôme Lebel * Tyler Brock * Wisdom Omuya -- Jason Carey mongo-c-driver 1.0.0 ==================== It is my very distinct pleasure to announce to you the 1.0 release of the MongoDB C driver! This is the culmination of just over a year of work and could not have been done without the help of our wonderful community. Thanks to everyone who contributed to the development of this driver! * Christian Hergert * Jason Carey * Gary Murakami * Christian Heckl * Frank Watson Song * Hannes Magnusson * JeÌroÌ‚me Lebel * Kyle Suarez * Maga Napanga * Michael Kuhn * Vincent Giersch * essentia44 * yuqing Happy Hacking! -- Christian Hergert mongo-c-driver 0.98.2 ===================== One final step before our journey to 1.0! This is a relatively small release, adding some features needed for drivers building on top of the C driver. A new libmongoc-priv.so library is installed that does not have symbols hidden. You can access private headers via the -private.h variants. This means you will need to recompile your project every time the library is changed (if you use those private headers, as they are subject to change). A special thanks to Hannes Magnusson for patches in this release. See `git shortlog 0.98.0..0.98.2` for a list of all the changes. -- Christian Hergert mongo-c-driver 0.98.0 ===================== Another step in the rapidly approaching path to 1.0! This release is primarily a bugfix release and stablization effort as we approach 1.0 of the MongoDB C driver. This release requires 0.98.0 of Libbson for improvements to the memory management system. You can now setup custom memory allocators at the start of the process. This is a RC release that with a few improvements will likely become 1.0. A special thanks to the following for patches in this cycle: * Kyle Suarez * yuqing See `git shortlog 0.96.4..0.98.0` for a list of all the changes. -- Christian Hergert mongo-c-driver 0.96.4 ===================== Another incremental feature update and bugfix release! In this release, you will find the following changes: * build/mci.sh script for automatically building Debian packages, RPMs, and Solaris packaging based on the host operating system. * Various libbson improvements, now depending on 0.8.4. * Alignment fixes for Solaris Studio C compiler via libbson. * Addition of mongoc_gridfs_remove_by_filename() for removing a file from gridfs by filename. * client command functions can now take a fully qualified namespace. * collections can now support names that indicate a command namespace. * Commands will no longer fail if they do not contain an "ok" field. * OP_QUERY will now set the slaveOk bit in the wire protocol if * readPreferences are set to non-PRIMARY. * Various documentation and build fixes. Thanks again to all the contributors, and happy hacking! mongo-c-driver 0.96.2 ===================== Hot on the heels of 0.96.0 we would like to present mongo-c-driver 0.96.2! This is primarily a bugfix release. Included in this release are: * Ensure batchSize is used in cursor GETMORE operations with `aggregate`. * Ensure enough buffer space is allocated for incoming RPC when buffering from a stream. * Require libbson 0.8.2 for more robust `bson_next_power_of_two()` when using `size_t` and BCON compilation fix with C++. * Handle cursor id's that are not 64-bit values in response from `aggregate` command. * Handle upsert on MongoDB < 2.6 when _id does not contain an `ObjectId`. * Use 100 for default batchSize in `aggregate` command. Happy Hacking! mongo-c-driver 0.96.0 ===================== It's that time again, time for another mongo-c-driver release! This release includes much new documentation, which can be found at http://docs.mongodb.org/ecosystem/drivers/c/. Additionally, this release improves support for various exotic systems. Solaris 10 is supported much better on SPARC and x86_64 based systems. Some workarounds for mixed-mode sharded-clusters have been added to improve resiliency when rolling upgrades are performed. Build improvements have been added to help us detect SASL and SSL implementations on platforms that do not support pkg-config. This should simplify building for some of you. We've added some more logging to SASL authentication to help debug authentication failures. A bug causing an abort() when SSL is used and a server is down has been fixed. We've renamed various _delete() functions to _remove() to provide consistency with other MongoDB drivers. You can now specify SSL options for client pools. -D_REENTRANT is always defined now on Solaris to help with errno detection. This may not have been done before if using a non-GCC platform with pthreads. A bug was fixed where timeouts could have been 1000x longer than expected due to failure to convert from microseconds to milliseconds. A bug was fixed with authentication in sharded cluster and replica set scenarios. Happy Hacking! mongo-c-driver 0.94.2 ===================== Hot on the heels of 0.94.0 is 0.94.2, a bugfix release. A bug has been fixed when using TLS streams and large result sets. In this release, we added support for Sun's C compiler (Sun Pro C) on Solaris. This allows for builds on Solaris 10 with SPARC using the native toolchain. This release contains a couple of fixes in libbson as well. Keep those bug reports coming, and as always, Happy Hacking! mongo-c-driver 0.94.0 ===================== The mongo-c-driver team is proud to announce the release of 0.94.0. This release is a followup to the previous release adding more features to be found in MongoDB 2.6. You will find some new API's, bug fixes, and more documentation. Under the hood, 0.94.0 uses the new write-commands as part of MongoDB 2.6 when it discovers it is communicating with a MongoDB server. There is now a bulk operation API (See `mongoc-bulk-operation.h`). Helpers for common server commands have been added. You can find most of them `mongoc-collection.h`. To simply using mongo-c-driver from Windows, we've included pre-built binaries on the release page. Thanks to all of the contributors this release! Happy Hacking! mongo-c-driver 0.92.0 ===================== The mongo-c-driver team is proud to announce the release of 0.92.0. This release is the culimation of a few months work and has many bug fixes and new features. It contains over 350 commits from 4 authors since the 0.90.0 release. The mongo-c-driver release tarballs now contain a bundled copy of libbson. If you do not have libbson installed or the system installed libbson is too old, the bundled copy of libbson will be installed. * Revamped build system to simplify installation. * Windows Vista and newer support. * Various GridFS fixes and features. * Kerberos support via cyrus-sasl. * Various SSL improvements. * Support for Solaris 11, FreeBSD 10, RHEL 5+, and SmartOS. * A new client side expression matcher to perform basic query processing. It can perform queries such as {'field': {'$in': [1,2,3]}}. See mongoc_matcher_t for more information. * A new socket abstraction for platform independent network sockets. * A new mongoc-dump example for how to write a simple mongodump replacement. * Counters can use rdtscp instruction on Core iX systems for very fast counters. * configure has new options. If in doubt, the defaults are sensible. * --enable-coverage=yes|no * --enable-debug=yes|no * --enable-debug-symbols=yes|no * --enable-hardening=yes|no * --enable-optimizations=yes|no * --enable-ssl=yes|no * --enable-sasl=yes|no * --enable-tracing=yes|no * --with-libbson=auto|system|bundled mongo-c-driver 0.92.0 requires libbson 0.6.4 or newer. Happy Hacking! Libmongoc 0.90.0 ================ This is the initial release of the new Libmongoc. We chose 0.90.0 for the release version to differentiate ourselves from the, now legacy, version of libmongoc. We will rapidly work towards reaching an API/ABI stable library fit for a 1.0.0 release. Libmongoc is Apache licensed so it can be embedded in a multitude of scenarios. The API of 0.90.0 is completely different from the previous versions. We think this allowed us to create a high-quality library that you will enjoy using in your applications. Many outstanding bugs were closed in the process of creating Libbson 0.90.0. So if you had a pet issue, please take a look to see if it was resolved as part of this effort! Thanks, and enjoy developing your applications with libmongoc! libmongoc-1.3.1/README.rst000066400000000000000000000111111264720626300151570ustar00rootroot00000000000000============== mongo-c-driver ============== About ===== mongo-c-driver is a client library written in C for MongoDB. mongo-c-driver depends on `Libbson `_. Libbson will automatically be built if you do not have it installed on your system. Documentation / Support / Feedback ================================== The documentation is available at http://api.mongodb.org/c/current/. For issues with, questions about, or feedback for libmongoc, please look into our `support channels `_. Please do not email any of the libmongoc developers directly with issues or questions - you're more likely to get an answer on the `mongodb-user list`_ on Google Groups. Bugs / Feature Requests ======================= Think you’ve found a bug? Want to see a new feature in libmongoc? Please open a case in our issue management tool, JIRA: - `Create an account and login `_. - Navigate to `the CDRIVER project `_. - Click **Create Issue** - Please provide as much information as possible about the issue type and how to reproduce it. Bug reports in JIRA for all driver projects (i.e. CDRIVER, CSHARP, JAVA) and the Core Server (i.e. SERVER) project are **public**. How To Ask For Help ------------------- If you are having difficulty building the driver after reading the below instructions, please email the `mongodb-user list`_ to ask for help. Please include in your email all of the following information: - The version of the driver you are trying to build (branch or tag). - Examples: master branch, 1.2.1 tag - Host OS, version, and architecture. - Examples: Windows 8 64-bit x86, Ubuntu 12.04 32-bit x86, OS X Mavericks - C Compiler and version. - Examples: GCC 4.8.2, MSVC 2013 Express, clang 3.4, XCode 5 - The output of ``./autogen.sh`` or ``./configure`` (depending on whether you are building from a repository checkout or from a tarball). The output starting from "libbson was configured with the following options" is sufficient. - The text of the error you encountered. Failure to include the relevant information will result in additional round-trip communications to ascertain the necessary details, delaying a useful response. Here is a made-up example of a help request that provides the relevant information: Hello, I'm trying to build the C driver with SSL, from mongo-c-driver-1.2.1.tar.gz. I'm on Ubuntu 14.04, 64-bit Intel, with gcc 4.8.2. I run configure like:: $ ./configure --enable-sasl=yes checking for gcc... gcc checking whether the C compiler works... yes ... SNIPPED OUTPUT, but when you ask for help, include full output without any omissions ... checking for pkg-config... no checking for SASL... no checking for sasl_client_init in -lsasl2... no checking for sasl_client_init in -lsasl... no configure: error: You must install the Cyrus SASL libraries and development headers to enable SASL support. Can you tell me what I need to install? Thanks! .. _mongodb-user list: http://groups.google.com/group/mongodb-user Security Vulnerabilities ------------------------ If you’ve identified a security vulnerability in a driver or any other MongoDB project, please report it according to the `instructions here `_. Building the Driver from Source =============================== Detailed installation instructions are in the manual: http://api.mongodb.org/c/current/installing.html From a tarball -------------- Download the latest release from `the release page `_, then:: $ tar xzf mongo-c-driver-$ver.tar.gz $ cd mongo-c-driver-$ver $ ./configure $ make $ sudo make install To see all of the options available to you during configuration, run:: $ ./configure --help To build on Windows Vista or newer with Visual Studio 2010, do the following:: cd mongo-c-driver-$ver cd src\libbson cmake -DCMAKE_INSTALL_PREFIX=C:\usr -G "Visual Studio 10 Win64" . msbuild.exe ALL_BUILD.vcxproj msbuild.exe INSTALL.vcxproj cd ..\.. cmake -DCMAKE_INSTALL_PREFIX=C:\usr -DBSON_ROOT_DIR=C:\usr -G "Visual Studio 10 Win64" . msbuild.exe ALL_BUILD.vcxproj msbuild.exe INSTALL.vcxproj Building From Git ================= You can use the following to checkout and build mongo-c-driver:: $ git clone https://github.com/mongodb/mongo-c-driver.git $ cd mongo-c-driver $ git checkout x.y.z # To build a particular release $ ./autogen.sh --with-libbson=bundled $ make $ sudo make install libmongoc-1.3.1/VERSION_CURRENT000066400000000000000000000000061264720626300157430ustar00rootroot000000000000001.3.1 libmongoc-1.3.1/VERSION_RELEASED000066400000000000000000000000061264720626300160050ustar00rootroot000000000000001.3.1 libmongoc-1.3.1/autogen.sh000077500000000000000000000021051264720626300154740ustar00rootroot00000000000000#! /bin/sh # Allow invocation from a separate build directory; in that case, we change # to the source directory to run the auto*, then change back before running configure srcdir=`dirname "$0"` test -z "$srcdir" && srcdir=. ORIGDIR=`pwd` cd "$srcdir" || exit 1 if [ ! -f README ]; then ln -s README.rst README fi touch ChangeLog touch AUTHORS if test -z "$(which libtoolize)" && test -z "$(which glibtoolize)"; then echo "Error: libtoolize was not found on your system. Cannot continue." if test "$(uname)" = "Darwin"; then echo "On Darwin, this is named glibtoolize" fi exit 1 fi if [ -d .git ]; then git submodule init git submodule update cd src/libbson NOCONFIGURE=1 ./autogen.sh cd ../../ fi if test -z `which autoreconf`; then echo "Error: autoreconf not found, please install it." exit 1 fi autoreconf --force --verbose --install -I build/autotools $ACLOCAL_FLAGS|| exit $? rm -rf autom4te.cache cd "$ORIGDIR" || exit 1 if test -z "$NOCONFIGURE"; then "$srcdir"/configure $AUTOGEN_CONFIGURE_ARGS "$@" || exit $? fi libmongoc-1.3.1/build/000077500000000000000000000000001264720626300145745ustar00rootroot00000000000000libmongoc-1.3.1/build/.gitignore000066400000000000000000000000101264720626300165530ustar00rootroot00000000000000version libmongoc-1.3.1/build/autotools/000077500000000000000000000000001264720626300166255ustar00rootroot00000000000000libmongoc-1.3.1/build/autotools/AutoHarden.m4000066400000000000000000000047641264720626300211340ustar00rootroot00000000000000# We want to check for compiler flag support, but there is no way to make # clang's "argument unused" warning fatal. So we invoke the compiler through a # wrapper script that greps for this message. saved_CC="$CC" saved_CXX="$CXX" saved_LD="$LD" flag_wrap="$srcdir/scripts/wrap-compiler-for-flag-check" CC="$flag_wrap $CC" CXX="$flag_wrap $CXX" LD="$flag_wrap $LD" # We use the same hardening flags for C and C++. We must check that each flag # is supported by both compilers. AC_DEFUN([check_cc_cxx_flag], [AC_LANG_PUSH(C) AX_CHECK_COMPILE_FLAG([$1], [AC_LANG_PUSH(C++) AX_CHECK_COMPILE_FLAG([$1], [$2], [$3], [-Werror $4]) AC_LANG_POP(C++)], [$3], [-Werror $4]) AC_LANG_POP(C)]) AC_DEFUN([check_link_flag], [AX_CHECK_LINK_FLAG([$1], [$2], [$3], [-Werror $4])]) AC_ARG_ENABLE([hardening], [AS_HELP_STRING([--enable-hardening], [Enable compiler and linker options to frustrate memory corruption exploits @<:@yes@:>@])], [enable_hardening="$enableval"], [enable_hardening="yes"]) HARDEN_CFLAGS="" HARDEN_LDFLAGS="" AS_IF([test x"$enable_hardening" != x"no"], [ check_cc_cxx_flag([-fno-strict-overflow], [HARDEN_CFLAGS="$HARDEN_CFLAGS -fno-strict-overflow"]) # This one will likely succeed, even on platforms where it does nothing. check_cc_cxx_flag([-D_FORTIFY_SOURCE=2], [HARDEN_CFLAGS="$HARDEN_CFLAGS -D_FORTIFY_SOURCE=2"]) check_cc_cxx_flag([-fstack-protector-all], [check_link_flag([-fstack-protector-all], [HARDEN_CFLAGS="$HARDEN_CFLAGS -fstack-protector-all" check_cc_cxx_flag([-Wstack-protector], [HARDEN_CFLAGS="$HARDEN_CFLAGS -Wstack-protector"], [], [-fstack-protector-all]) check_cc_cxx_flag([--param ssp-buffer-size=1], [HARDEN_CFLAGS="$HARDEN_CFLAGS --param ssp-buffer-size=1"], [], [-fstack-protector-all])])]) # At the link step, we might want -pie (GCC) or -Wl,-pie (Clang on OS X) # # The linker checks also compile code, so we need to include -fPIE as well. check_cc_cxx_flag([-fPIE], [check_link_flag([-fPIE -pie], [HARDEN_CFLAGS="$HARDEN_CFLAGS -fPIE" HARDEN_LDFLAGS="$HARDEN_LDFLAGS -pie"], [check_link_flag([-fPIE -Wl,-pie], [HARDEN_CFLAGS="$HARDEN_CFLAGS -fPIE" HARDEN_LDFLAGS="$HARDEN_LDFLAGS -Wl,-pie"])])]) check_link_flag([-Wl,-z,relro], [HARDEN_LDFLAGS="$HARDEN_LDFLAGS -Wl,-z,relro" check_link_flag([-Wl,-z,now], [HARDEN_LDFLAGS="$HARDEN_LDFLAGS -Wl,-z,now"])])]) AC_SUBST([HARDEN_CFLAGS]) AC_SUBST([HARDEN_LDFLAGS]) # End of flag tests. CC="$saved_CC" CXX="$saved_CXX" LD="$saved_LD" libmongoc-1.3.1/build/autotools/CheckCompiler.m4000066400000000000000000000034161264720626300216030ustar00rootroot00000000000000# If CFLAGS and CXXFLAGS are unset, default to empty. # This is to tell automake not to include '-g' if C{XX,}FLAGS is not set. # For more info - http://www.gnu.org/software/automake/manual/autoconf.html#C_002b_002b-Compiler if test -z "$CXXFLAGS"; then CXXFLAGS="" fi if test -z "$CFLAGS"; then CFLAGS="" fi AC_PROG_CC AC_PROG_CXX # Check that an appropriate C compiler is available. c_compiler="unknown" AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #if !(defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)) #error Not a supported GCC compiler #endif #if defined(__GNUC__) #define GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) #if GCC_VERSION < 40100 #error Not a supported GCC compiler #endif #endif ])], [c_compiler="gcc"], []) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #if defined(__clang__) #define CLANG_VERSION (__clang_major__ * 10000 \ + __clang_minor__ * 100 \ + __clang_patchlevel__) #if CLANG_VERSION < 30300 #error Not a supported Clang compiler #endif #endif ])], [c_compiler="clang"], []) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #if !(defined(__SUNPRO_C)) #error Not a supported Sun compiler #endif ])], [c_compiler="sun"], []) AC_LANG_POP([C]) if test "$c_compiler" = "unknown"; then AC_MSG_ERROR([Compiler GCC >= 4.1 or Clang >= 3.3 is required for C compilation]) fi # GLibc 2.19 complains about both _BSD_SOURCE and _GNU_SOURCE. The _GNU_SOURCE # contains everything anyway. So just use that. AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #ifndef __GLIBC__ #error not glibc #endif ]], [])], LIBC_FEATURES="-D_GNU_SOURCE", LIBC_FEATURES="-D_BSD_SOURCE") AC_SUBST(LIBC_FEATURES) AC_C_CONST AC_C_INLINE AC_C_TYPEOF libmongoc-1.3.1/build/autotools/CheckHost.m4000066400000000000000000000013551264720626300207460ustar00rootroot00000000000000AC_CANONICAL_HOST os_win32=no os_linux=no os_freebsd=no os_gnu=no case "$host" in *-mingw*|*-*-cygwin*) os_win32=yes TARGET_OS=windows ;; *-*-*netbsd*) os_netbsd=yes TARGET_OS=unix ;; *-*-*freebsd*) os_freebsd=yes TARGET_OS=unix ;; *-*-*openbsd*) os_openbsd=yes TARGET_OS=unix ;; *-*-linux*) os_linux=yes os_gnu=yes TARGET_OS=unix ;; *-*-solaris*) os_solaris=yes TARGET_OS=unix ;; *-*-darwin*) os_darwin=yes TARGET_OS=unix ;; gnu*|k*bsd*-gnu*) os_gnu=yes TARGET_OS=unix ;; *) AC_MSG_WARN([*** Please add $host to configure.ac checks!]) ;; esac libmongoc-1.3.1/build/autotools/CheckProgs.m4000066400000000000000000000006231264720626300211200ustar00rootroot00000000000000AC_PATH_PROG(PERL, perl) if test -z "$PERL"; then AC_MSG_ERROR([You need 'perl' to compile libbson]) fi AC_PATH_PROG(MV, mv) if test -z "$MV"; then AC_MSG_ERROR([You need 'mv' to compile libbson]) fi AC_PATH_PROG(GREP, grep) if test -z "$GREP"; then AC_MSG_ERROR([You need 'grep' to compile libbson]) fi # Optional for documentation AC_PATH_PROG(YELP_BUILD, yelp-build) AC_PROG_INSTALL libmongoc-1.3.1/build/autotools/CheckSSL.m4000066400000000000000000000032631264720626300204720ustar00rootroot00000000000000AC_ARG_ENABLE([ssl], [AS_HELP_STRING([--enable-ssl=@<:@auto/yes/no@:>@], [Use OpenSSL for TLS connections and SCRAM-SHA-1 authentication. NOTE: OpenSSL is required for authenticating to MongoDB 3.0 and later])], [], [enable_ssl=auto]) AS_IF([test "$enable_ssl" != "no"],[ PKG_CHECK_MODULES(SSL, [openssl], [enable_ssl=yes], [ AS_IF([test "$enable_ssl" != "no"],[ AC_CHECK_LIB([ssl],[SSL_library_init],[have_ssl_lib=yes],[have_ssl_lib=no]) AC_CHECK_LIB([crypto],[CRYPTO_set_locking_callback],[have_crypto_lib=yes],[have_crypto_lib=no]) if test "$enable_ssl" = "yes"; then if test "$have_ssl_lib" = "no" -o "$have_crypto_lib" = "no" ; then AC_MSG_ERROR([You must install the OpenSSL libraries and development headers to enable SSL support.]) fi fi AC_CHECK_HEADERS([openssl/bio.h openssl/ssl.h openssl/err.h openssl/crypto.h], [have_ssl_headers=yes], [have_ssl_headers=no]) if test "$have_ssl_headers" = "no" -a "$enable_ssl" = "yes" ; then AC_MSG_ERROR([You must install the OpenSSL development headers to enable SSL support.]) fi if test "$have_ssl_headers" = "yes" -a "$have_ssl_lib" = "yes" -a "$have_crypto_lib" = "yes"; then SSL_LIBS="-lssl -lcrypto" enable_ssl=yes else enable_ssl=no fi ]) ]) ]) AM_CONDITIONAL([ENABLE_SSL], [test "$enable_ssl" = "yes"]) AC_SUBST(SSL_CFLAGS) AC_SUBST(SSL_LIBS) dnl Let mongoc-config.h.in know about SSL status. if test "$enable_ssl" = "yes" ; then AC_SUBST(MONGOC_ENABLE_SSL, 1) else AC_SUBST(MONGOC_ENABLE_SSL, 0) fi libmongoc-1.3.1/build/autotools/CheckSasl.m4000066400000000000000000000035451264720626300207360ustar00rootroot00000000000000AC_ARG_ENABLE([sasl], [AS_HELP_STRING([--enable-sasl=@<:@auto/yes/no@:>@], [Use libsasl for Kerberos.])], [], [enable_sasl=auto]) sasl_mode=no AS_IF([test "$enable_sasl" != "no"],[ PKG_CHECK_MODULES(SASL, [libsasl2], [sasl_mode=sasl2], [ AS_IF([test "$enable_sasl" != "no"],[ AC_CHECK_LIB([sasl2],[sasl_client_init],[have_sasl2_lib=yes],[have_sasl2_lib=no]) AC_CHECK_LIB([sasl],[sasl_client_init],[have_sasl_lib=yes],[have_sasl_lib=no]) if test "$have_sasl_lib" = "no" -a "$have_sasl2_lib" = "no" -a "$enable_sasl" = "yes" ; then AC_MSG_ERROR([You must install the Cyrus SASL libraries and development headers to enable SASL support.]) fi AC_CHECK_HEADER([sasl/sasl.h],[have_sasl_headers=yes],[have_sasl_headers=no]) if test "$have_sasl_headers" = "no" -a "$enable_sasl" = "yes" ; then AC_MSG_ERROR([You must install the Cyrus SASL development headers to enable SASL support.]) fi if test "$have_sasl_headers" -a "$have_sasl2_lib" = "yes" ; then sasl_mode=sasl2 SASL_LIBS=-lsasl2 fi if test "$have_sasl_headers" -a "$have_sasl_lib" = "yes" ; then sasl_mode=sasl SASL_LIBS=-lsasl fi ]) ]) ]) AM_CONDITIONAL([ENABLE_SASL], [test "$sasl_mode" != "no"]) AC_SUBST(SASL_CFLAGS) AC_SUBST(SASL_LIBS) dnl Let mongoc-config.h.in know about SASL status. if test "$sasl_mode" != "no" ; then AC_SUBST(MONGOC_ENABLE_SASL, 1) AC_CHECK_LIB([sasl2],[sasl_client_done], [have_sasl_client_done=yes], [have_sasl_client_done=no]) if test "$have_sasl_client_done" = "yes" ; then AC_SUBST(MONGOC_HAVE_SASL_CLIENT_DONE, 1) else AC_SUBST(MONGOC_HAVE_SASL_CLIENT_DONE, 0) fi else AC_SUBST(MONGOC_ENABLE_SASL, 0) AC_SUBST(MONGOC_HAVE_SASL_CLIENT_DONE, 0) fi libmongoc-1.3.1/build/autotools/CheckTarget.m4000066400000000000000000000011471264720626300212560ustar00rootroot00000000000000AC_CANONICAL_SYSTEM enable_crosscompile=no if test "x$host" != "x$target"; then enable_crosscompile=yes case "$target" in *-mingw*|*-*-cygwin*) TARGET_OS=windows ;; arm*-darwin*) TARGET_OS=unix ;; powerpc64-*-linux-gnu) TARGET_OS=unix ;; arm*-linux-*) TARGET_OS=unix ;; *) AC_MSG_ERROR([Cross compiling is not supported for target $target]) ;; esac fi AC_SUBST(BSON_OS, 1) if test "$TARGET_OS" = "windows"; then AC_SUBST(BSON_OS, 2) fi libmongoc-1.3.1/build/autotools/Coverage.m4000066400000000000000000000003141264720626300206200ustar00rootroot00000000000000COVERAGE_CFLAGS="" COVERAGE_LDFLAGS="" if test "$enable_coverage" = "yes"; then COVERAGE_CFLAGS="--coverage -g" COVERAGE_LDFLAGS="-lgcov" fi AC_SUBST(COVERAGE_CFLAGS) AC_SUBST(COVERAGE_LDFLAGS) libmongoc-1.3.1/build/autotools/FindDependencies.m4000066400000000000000000000022361264720626300222610ustar00rootroot00000000000000 # Solaris needs to link against socket libs. if test "$os_solaris" = "yes"; then CFLAGS="$CFLAGS -D__EXTENSIONS__" CFLAGS="$CFLAGS -D_XOPEN_SOURCE=1" CFLAGS="$CFLAGS -D_XOPEN_SOURCE_EXTENDED=1" LDFLAGS="$LDFLAGS -lsocket -lnsl" fi # Check if we should enable the bundled libbson. if test "$with_libbson" = "auto"; then PKG_CHECK_MODULES(BSON, libbson-1.0 >= libbson_required_version, [with_libbson=system], [with_libbson=bundled]) fi AM_CONDITIONAL(ENABLE_LIBBSON, [test "$with_libbson" = "bundled"]) # Check for shm functions. AC_CHECK_FUNCS([shm_open], [SHM_LIB=], [AC_CHECK_LIB([rt], [shm_open], [SHM_LIB=-lrt], [SHM_LIB=])]) AC_SUBST([SHM_LIB]) # Check for sched_getcpu AC_CHECK_FUNCS([sched_getcpu]) # Check for clock_gettime AC_SEARCH_LIBS([clock_gettime], [rt], [ AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Have clock_gettime]) ]) AS_IF([test "$ac_cv_search_clock_gettime" = "-lrt"], [LDFLAGS="$LDFLAGS -lrt"]) AS_IF([test "$enable_rdtscp" = "yes"], [CPPFLAGS="$CPPFLAGS -DENABLE_RDTSCP"]) AS_IF([test "$enable_shm_counters" = "yes"], [CPPFLAGS="$CPPFLAGS -DMONGOC_ENABLE_SHM_COUNTERS"]) AX_PTHREAD libmongoc-1.3.1/build/autotools/LDVersionScript.m4000066400000000000000000000034141264720626300221230ustar00rootroot00000000000000# ld-version-script.m4 serial 3 dnl Copyright (C) 2008-2013 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Simon Josefsson # FIXME: The test below returns a false positive for mingw # cross-compiles, 'local:' statements does not reduce number of # exported symbols in a DLL. Use --disable-ld-version-script to work # around the problem. # gl_LD_VERSION_SCRIPT # -------------------- # Check if LD supports linker scripts, and define automake conditional # HAVE_LD_VERSION_SCRIPT if so. AC_DEFUN([gl_LD_VERSION_SCRIPT], [ AC_ARG_ENABLE([ld-version-script], AS_HELP_STRING([--enable-ld-version-script], [enable linker version script (default is enabled when possible)]), [have_ld_version_script=$enableval], []) if test -z "$have_ld_version_script"; then AC_MSG_CHECKING([if LD -Wl,--version-script works]) save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" cat > conftest.map < conftest.map <= libbson_required_version], [with_libbson=system], [with_libbson=bundled])]) # If we are to use the system, check for libbson enforcing success. AS_IF([test "x${with_libbson}" = xsystem], [PKG_CHECK_MODULES(BSON, [libbson-1.0 >= libbson_required_version], [], [AC_MSG_ERROR([ -------------------------------------- The libbson-1.0 library could not be found on your system. Please install libbson-1.0 development package or set --with-libbson=auto. -------------------------------------- ])])]) # If we are using the bundled libbson, recurse into its configure. AS_IF([test "x${with_libbson}" = xbundled],[ AC_CONFIG_SUBDIRS([src/libbson]) AC_SUBST(BSON_CFLAGS, "-I${srcdir}/src/libbson/src/bson -Isrc/libbson/src/bson") AC_SUBST(BSON_LIBS, "src/libbson/libbson-1.0.la") ]) libmongoc-1.3.1/build/autotools/MaintainerFlags.m4000066400000000000000000000036321264720626300221370ustar00rootroot00000000000000AS_IF([test "x$enable_maintainer_flags" = "xyes" && test "x$GCC" = "xyes"], [check_cc_cxx_flag([-Wall], [CFLAGS="$CFLAGS -Wall"]) check_cc_cxx_flag([-Waggregate-return], [CFLAGS="$CFLAGS -Waggregate-return"]) check_cc_cxx_flag([-Wcast-align], [CFLAGS="$CFLAGS -Wcast-align"]) check_cc_cxx_flag([-Wdeclaration-after-statement], [CFLAGS="$CFLAGS -Wdeclaration-after-statement"]) check_cc_cxx_flag([-Wempty-body], [CFLAGS="$CFLAGS -Wempty-body"]) check_cc_cxx_flag([-Wformat], [CFLAGS="$CFLAGS -Wformat"]) check_cc_cxx_flag([-Wformat-nonliteral], [CFLAGS="$CFLAGS -Wformat-nonliteral"]) check_cc_cxx_flag([-Wformat-security], [CFLAGS="$CFLAGS -Wformat-security"]) check_cc_cxx_flag([-Winit-self], [CFLAGS="$CFLAGS -Winit-self"]) check_cc_cxx_flag([-Winline], [CFLAGS="$CFLAGS -Winline"]) check_cc_cxx_flag([-Wmissing-include-dirs], [CFLAGS="$CFLAGS -Wmissing-include-dirs"]) check_cc_cxx_flag([-Wno-strict-aliasing], [CFLAGS="$CFLAGS -Wno-strict-aliasing"]) check_cc_cxx_flag([-Wno-uninitialized], [CFLAGS="$CFLAGS -Wno-uninitialized"]) check_cc_cxx_flag([-Wredundant-decls], [CFLAGS="$CFLAGS -Wredundant-decls"]) check_cc_cxx_flag([-Wreturn-type], [CFLAGS="$CFLAGS -Wreturn-type"]) check_cc_cxx_flag([-Wshadow], [CFLAGS="$CFLAGS -Wshadow"]) check_cc_cxx_flag([-Wswitch-default], [CFLAGS="$CFLAGS -Wswitch-default"]) check_cc_cxx_flag([-Wswitch-enum], [CFLAGS="$CFLAGS -Wswitch-enum"]) check_cc_cxx_flag([-Wundef], [CFLAGS="$CFLAGS -Wundef"]) check_cc_cxx_flag([-Wuninitialized], [CFLAGS="$CFLAGS -Wuninitialized"])]) libmongoc-1.3.1/build/autotools/Optimizations.m4000066400000000000000000000014251264720626300217420ustar00rootroot00000000000000OPTIMIZE_CFLAGS="" OPTIMIZE_LDFLAGS="" dnl Check if we should use -Bsymbolic AS_IF([test "$enable_optimizations" != "no"], [ check_link_flag([-Wl,-Bsymbolic], [OPTIMIZE_LDFLAGS="$OPTIMIZE_LDFLAGS -Wl,-Bsymbolic"]) dnl Add the appropriate 'O' level for optimized builds. CFLAGS="$CFLAGS -O2" ]) AC_SUBST(OPTIMIZE_CFLAGS) AC_SUBST(OPTIMIZE_LDFLAGS) # Add '-g' flag to gcc to build with debug symbols. if test "$enable_debug_symbols" = "min"; then CFLAGS="$CFLAGS -g1" elif test "$enable_debug_symbols" != "no"; then CFLAGS="$CFLAGS -g" fi AS_IF([test $"enable_debug" = "no"], [CPPFLAGS="$CPPFLAGS -DBSON_DISABLE_ASSERT" CPPFLAGS="$CPPFLAGS -DBSON_DISABLE_CHECKS"]) AS_IF([test "$enable_tracing" = "yes"], [CPPFLAGS="$CPPFLAGS -DMONGOC_TRACE"]) libmongoc-1.3.1/build/autotools/PlatformFlags.m4000066400000000000000000000013641264720626300216340ustar00rootroot00000000000000dnl check_cc_cxx_flag is defined in build/autotools/AutoHarden.m4 dnl Ignore OpenSSL deprecation warnings on OSX AS_IF([test "$os_darwin" = "yes"], [check_cc_cxx_flag([-Wno-deprecated-declarations], [CFLAGS="$CFLAGS -Wno-deprecated-declarations"])]) dnl We know there are some cast-align issues on OSX AS_IF([test "$os_darwin" = "yes"], [check_cc_cxx_flag([-Wno-cast-align], [CFLAGS="$CFLAGS -Wno-cast-align"])]) AS_IF([test "$os_darwin" = "yes"], [check_cc_cxx_flag([-Wno-unneeded-internal-declaration], [CFLAGS="$CFLAGS -Wno-unneeded-internal-declaration"])]) dnl We know there are some cast-align issues on Solaris AS_IF([test "$os_solaris" = "yes"], [check_cc_cxx_flag([-Wno-cast-align], [CFLAGS="$CFLAGS -Wno-cast-align"])]) libmongoc-1.3.1/build/autotools/PrintBuildConfiguration.m4000066400000000000000000000026711264720626300237010ustar00rootroot00000000000000AC_OUTPUT if test -n "$MONGOC_PRERELEASE_VERSION"; then cat << EOF *** IMPORTANT *** This is an unstable version of libmongoc. It is for test purposes only. Please, DO NOT use it in a production environment. It will probably crash and you will lose your data. Additionally, the API/ABI may change during the course of development. Thanks, The libmongoc team. *** END OF WARNING *** EOF fi echo " libmongoc $MONGOC_VERSION was configured with the following options: Build configuration: Enable debugging (slow) : ${enable_debug} Compile with debug symbols (slow) : ${enable_debug_symbols} Enable GCC build optimization : ${enable_optimizations} Enable automatic binary hardening : ${enable_hardening} Code coverage support : ${enable_coverage} Cross Compiling : ${enable_crosscompile} Fast counters : ${enable_rdtscp} Shared memory performance counters : ${enable_shm_counters} SASL : ${sasl_mode} SSL : ${enable_ssl} Libbson : ${with_libbson} Documentation: man : ${enable_man_pages} HTML : ${enable_html_docs} " libmongoc-1.3.1/build/autotools/ReadCommandLineArguments.m4000066400000000000000000000077571264720626300237570ustar00rootroot00000000000000AC_MSG_CHECKING([whether to do a debug build]) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [turn on debugging [default=no]]), [],[enable_debug="no"]) AC_MSG_RESULT([$enable_debug]) AC_MSG_CHECKING([whether to enable tracing]) AC_ARG_ENABLE(tracing, AC_HELP_STRING([--enable-tracing], [turn on tracing [default=no]]), [],[enable_tracing="no"]) AC_MSG_RESULT([$enable_tracing]) AC_MSG_CHECKING([whether to enable optimized builds]) AC_ARG_ENABLE(optimizations, AC_HELP_STRING([--enable-optimizations], [turn on build-time optimizations [default=yes]]), [enable_optimizations=$enableval], [ if test "$enable_debug" = "yes"; then enable_optimizations="no"; else enable_optimizations="yes"; fi ]) AC_MSG_RESULT([$enable_optimizations]) AC_MSG_CHECKING([whether to enable shared memory performance counters]) AC_ARG_ENABLE(shm_counters, AC_HELP_STRING([--enable-shm-counters], [turn on shared memory performance counters [default=yes]]), [],[enable_shm_counters="yes"]) AC_MSG_RESULT([$enable_shm_counters]) AC_MSG_CHECKING([whether to enable code coverage support]) AC_ARG_ENABLE(coverage, AC_HELP_STRING([--enable-coverage], [enable code coverage support [default=no]]), [], [enable_coverage="no"]) AC_MSG_RESULT([$enable_coverage]) AC_MSG_CHECKING([whether to enable debug symbols]) AC_ARG_ENABLE(debug_symbols, AC_HELP_STRING([--enable-debug-symbols=yes|no|min|full], [enable debug symbols default=no, default=yes for debug builds]), [ case "$enable_debug_symbols" in yes) enable_debug_symbols="full" ;; no|min|full) ;; *) AC_MSG_ERROR([Invalid debug symbols option: must be yes, no, min or full.]) ;; esac ], [ if test "$enable_debug" = "yes"; then enable_debug_symbols="yes"; else enable_debug_symbols="no"; fi ]) AC_MSG_RESULT([$enable_debug_symbols]) AC_ARG_ENABLE([rdtscp], [AS_HELP_STRING([--enable-rdtscp=@<:@no/yes@:>@], [Use rdtscp for per-cpu counters @<:@default=no@:>@])], [], [enable_rdtscp=no]) # use strict compiler flags only on development releases m4_define([maintainer_flags_default], [m4_ifset([MONGOC_PRERELEASE_VERSION], [yes], [no])]) AC_ARG_ENABLE([maintainer-flags], [AS_HELP_STRING([--enable-maintainer-flags=@<:@no/yes@:>@], [Use strict compiler flags @<:@default=]maintainer_flags_default[@:>@])], [], [enable_maintainer_flags=maintainer_flags_default]) # Check if we should use the bundled (git submodule) libbson AC_ARG_WITH(libbson, AC_HELP_STRING([--with-libbson=@<:@auto/system/bundled@:>@], [use system installed libbson or bundled libbson. default=auto]), [], [with_libbson=auto]) AS_IF([test "x$with_libbson" != xbundled && test "x$with_libbson" != xsystem], [with_libbson=auto]) AC_ARG_ENABLE([html-docs], [AS_HELP_STRING([--enable-html-docs=@<:@yes/no@:>@], [Build HTML documentation.])], [], [enable_html_docs=no]) AC_ARG_ENABLE([man-pages], [AS_HELP_STRING([--enable-man-pages=@<:@yes/no@:>@], [Build and install man-pages.])], [], [enable_man_pages=no]) AC_ARG_ENABLE([yelp], [AS_HELP_STRING([--enable-yelp=@<:@yes/no@:>@], [Install yelp manuals.])], [], [enable_yelp=no]) AC_ARG_ENABLE([examples], [AS_HELP_STRING([--enable-examples=@<:@yes/no@:>@], [Build MongoDB C Driver examples.])], [], [enable_examples=yes]) AC_ARG_ENABLE([tests], [AS_HELP_STRING([--enable-tests=@<:@yes/no@:>@], [Build MongoDB C Driver tests.])], [], [enable_tests=yes]) libmongoc-1.3.1/build/autotools/SetupAutomake.m4000066400000000000000000000033051264720626300216570ustar00rootroot00000000000000m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AM_PROG_CC_C_O # OS Conditionals. AM_CONDITIONAL([OS_WIN32],[test "$os_win32" = "yes"]) AM_CONDITIONAL([OS_UNIX],[test "$os_win32" = "no"]) AM_CONDITIONAL([OS_LINUX],[test "$os_linux" = "yes"]) AM_CONDITIONAL([OS_GNU],[test "$os_gnu" = "yes"]) AM_CONDITIONAL([OS_DARWIN],[test "$os_darwin" = "yes"]) AM_CONDITIONAL([OS_FREEBSD],[test "$os_freebsd" = "yes"]) AM_CONDITIONAL([OS_SOLARIS],[test "$os_solaris" = "yes"]) # Compiler Conditionals. AM_CONDITIONAL([COMPILER_GCC],[test "$c_compiler" = "gcc" && test "$cxx_compiler" = "g++"]) AM_CONDITIONAL([COMPILER_CLANG],[test "$c_compiler" = "clang" && test "$cxx_compiler" = "clang++"]) # Feature Conditionals AM_CONDITIONAL([ENABLE_DEBUG],[test "$enable_debug" = "yes"]) # C99 Features AM_CONDITIONAL([ENABLE_STDBOOL],[test "$enable_stdbool" = "yes"]) # Should we use pthreads AM_CONDITIONAL([ENABLE_PTHREADS],[test "$enable_pthreads" = "yes"]) # Should we compile the bundled libbson AM_CONDITIONAL([WITH_LIBBSON],[test "$with_libbson" = "bundled"]) # Should we avoid extra BSON_LIBS when linking (SunStudio) AM_CONDITIONAL([EXPLICIT_LIBS],[test "$with_gnu_ld" = "yes"]) # Should we build the examples. AM_CONDITIONAL([ENABLE_EXAMPLES],[test "$enable_examples" = "yes"]) # Should we build the tests. AM_CONDITIONAL([ENABLE_TESTS],[test "$enable_tests" = "yes"]) # Should we build man pages AM_CONDITIONAL([ENABLE_MAN_PAGES],[test "$enable_man_pages" = "yes"]) # Should we build HTML documentation AM_CONDITIONAL([ENABLE_HTML_DOCS],[test "$enable_html_docs" = "yes"]) AS_IF([test "$enable_html_docs" = "yes" && test -z "$YELP_BUILD"], [AC_MSG_ERROR([yelp-build must be installed to generate HTML documentation.])]) libmongoc-1.3.1/build/autotools/SetupLibtool.m4000066400000000000000000000001111264720626300215050ustar00rootroot00000000000000LT_PREREQ([2.2]) AC_DISABLE_STATIC AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL libmongoc-1.3.1/build/autotools/Versions.m4000066400000000000000000000035571264720626300207110ustar00rootroot00000000000000MONGOC_CURRENT_FILE=${srcdir}/VERSION_CURRENT MONGOC_VERSION=$(cat $MONGOC_CURRENT_FILE) MONGOC_MAJOR_VERSION=$(cut -d- -f1 $MONGOC_CURRENT_FILE | cut -d. -f1) MONGOC_MINOR_VERSION=$(cut -d- -f1 $MONGOC_CURRENT_FILE | cut -d. -f2) MONGOC_MICRO_VERSION=$(cut -d- -f1 $MONGOC_CURRENT_FILE | cut -d. -f3) MONGOC_PRERELEASE_VERSION=$(cut -s -d- -f2 $MONGOC_CURRENT_FILE) AC_SUBST(MONGOC_VERSION) AC_SUBST(MONGOC_MAJOR_VERSION) AC_SUBST(MONGOC_MINOR_VERSION) AC_SUBST(MONGOC_MICRO_VERSION) AC_SUBST(MONGOC_PRERELEASE_VERSION) MONGOC_RELEASED_FILE=${srcdir}/VERSION_RELEASED MONGOC_RELEASED_VERSION=$(cat $MONGOC_RELEASED_FILE) MONGOC_RELEASED_MAJOR_VERSION=$(cut -d- -f1 $MONGOC_RELEASED_FILE | cut -d. -f1) MONGOC_RELEASED_MINOR_VERSION=$(cut -d- -f1 $MONGOC_RELEASED_FILE | cut -d. -f2) MONGOC_RELEASED_MICRO_VERSION=$(cut -d- -f1 $MONGOC_RELEASED_FILE | cut -d. -f3) MONGOC_RELEASED_PRERELEASE_VERSION=$(cut -s -d- -f2 $MONGOC_RELEASED_FILE) AC_SUBST(MONGOC_RELEASED_VERSION) AC_SUBST(MONGOC_RELEASED_MAJOR_VERSION) AC_SUBST(MONGOC_RELEASED_MINOR_VERSION) AC_SUBST(MONGOC_RELEASED_MICRO_VERSION) AC_SUBST(MONGOC_RELEASED_PRERELEASE_VERSION) AC_MSG_NOTICE([Current version (from VERSION_CURRENT file): $MONGOC_VERSION]) if test "x$MONGOC_RELEASED_PRERELEASE_VERSION" != "x"; then AC_ERROR([RELEASED_VERSION file has prerelease version $MONGOC_RELEASED_VERSION]) fi if test "x$MONGOC_VERSION" != "x$MONGOC_RELEASED_VERSION"; then AC_MSG_NOTICE([Most recent release (from VERSION_RELEASED file): $MONGOC_RELEASED_VERSION]) if test "x$MONGOC_PRERELEASE_VERSION" = "x"; then AC_ERROR([Current version ($MONGOC_PRERELEASE_VERSION) must be a prerelease (with "-dev", "-beta", etc.) or equal to previous release]) fi fi dnl So far, we've synchronized libbson and mongoc versions. m4_define([libbson_required_version], $MONGOC_RELEASED_VERSION) m4_define([sasl_required_version], [2.1.6]) libmongoc-1.3.1/build/autotools/WeakSymbols.m4000066400000000000000000000004011264720626300213220ustar00rootroot00000000000000AC_MSG_CHECKING(if weak symbols are supported) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ __attribute__((weak)) void __dummy(void *x) { } void f(void *x) { __dummy(x); } ]], [[ ]] )], [AC_MSG_RESULT(yes) AC_SUBST(MONGOC_HAVE_WEAK_SYMBOLS, 1)], [AC_MSG_RESULT(no)]) libmongoc-1.3.1/build/autotools/m4/000077500000000000000000000000001264720626300171455ustar00rootroot00000000000000libmongoc-1.3.1/build/autotools/m4/.gitignore000066400000000000000000000000771264720626300211410ustar00rootroot00000000000000lt~obsolete.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 libtool.m4 libmongoc-1.3.1/build/autotools/m4/ac_check_typedef.m4000066400000000000000000000026401264720626300226510ustar00rootroot00000000000000dnl @synopsis AC_CHECK_TYPEDEF_(TYPEDEF, HEADER [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]) dnl dnl check if the given typedef-name is recognized as a type. The trick dnl is to use a sizeof(TYPEDEF) and see if the compiler is happy with dnl that. dnl dnl this can be thought of as a mixture of dnl AC_CHECK_TYPE(TYPEDEF,DEFAULT) and dnl AC_CHECK_LIB(LIBRARY,FUNCTION,ACTION-IF-FOUND,ACTION-IF-NOT-FOUND) dnl dnl a convenience macro AC_CHECK_TYPEDEF_ is provided that will not dnl emit any message to the user - it just executes one of the actions. dnl dnl @category C dnl @author Guido U. Draheim dnl @version 2006-10-13 dnl @license GPLWithACException AC_DEFUN([AC_CHECK_TYPEDEF_], [dnl ac_lib_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` AC_CACHE_VAL(ac_cv_lib_$ac_lib_var, [ eval "ac_cv_type_$ac_lib_var='not-found'" ac_cv_check_typedef_header=`echo ifelse([$2], , stddef.h, $2)` AC_TRY_COMPILE( [#include <$ac_cv_check_typedef_header>], [int x = sizeof($1); x = x;], eval "ac_cv_type_$ac_lib_var=yes" , eval "ac_cv_type_$ac_lib_var=no" ) if test `eval echo '$ac_cv_type_'$ac_lib_var` = "no" ; then ifelse([$4], , :, $4) else ifelse([$3], , :, $3) fi ])]) dnl AC_CHECK_TYPEDEF(TYPEDEF, HEADER [, ACTION-IF-FOUND, dnl [, ACTION-IF-NOT-FOUND ]]) AC_DEFUN([AC_CHECK_TYPEDEF], [dnl AC_MSG_CHECKING([for $1 in $2]) AC_CHECK_TYPEDEF_($1,$2,AC_MSG_RESULT(yes),AC_MSG_RESULT(no))dnl ]) libmongoc-1.3.1/build/autotools/m4/ac_compile_check_sizeof.m4000066400000000000000000000015661264720626300242260ustar00rootroot00000000000000AC_DEFUN([AC_COMPILE_CHECK_SIZEOF], [changequote(<<, >>)dnl dnl The name to #define. define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl dnl The cache variable name. define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl changequote([, ])dnl AC_MSG_CHECKING(size of $1) AC_CACHE_VAL(AC_CV_NAME, [for ac_size in 4 8 1 2 16 $2 ; do # List sizes in rough order of prevalence. AC_TRY_COMPILE([#include "confdefs.h" #include <sys/types.h> $2 ], [switch (0) case 0: case (sizeof ($1) == $ac_size):;], AC_CV_NAME=$ac_size) if test x$AC_CV_NAME != x ; then break; fi done ]) if test x$AC_CV_NAME = x ; then AC_MSG_ERROR([cannot determine a size for $1]) fi AC_MSG_RESULT($AC_CV_NAME) AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The number of bytes in type $1]) undefine([AC_TYPE_NAME])dnl undefine([AC_CV_NAME])dnl ]) libmongoc-1.3.1/build/autotools/m4/ac_create_stdint_h.m4000066400000000000000000000366221264720626300232220ustar00rootroot00000000000000dnl @synopsis AC_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])] dnl dnl the "ISO C9X: 7.18 Integer types " section requires the dnl existence of an include file that defines a set of dnl typedefs, especially uint8_t,int32_t,uintptr_t. Many older dnl installations will not provide this file, but some will have the dnl very same definitions in . In other enviroments we can dnl use the inet-types in which would define the typedefs dnl int8_t and u_int8_t respectivly. dnl dnl This macros will create a local "_stdint.h" or the headerfile given dnl as an argument. In many cases that file will just have a singular dnl "#include " or "#include " statement, while dnl in other environments it will provide the set of basic 'stdint's dnl defined: dnl int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t dnl int_least32_t.. int_fast32_t.. intmax_t which may or may not rely dnl on the definitions of other files, or using the dnl AC_COMPILE_CHECK_SIZEOF macro to determine the actual sizeof each dnl type. dnl dnl if your header files require the stdint-types you will want to dnl create an installable file mylib-int.h that all your other dnl installable header may include. So if you have a library package dnl named "mylib", just use dnl dnl AC_CREATE_STDINT_H(mylib-int.h) dnl dnl in configure.in and go to install that very header file in dnl Makefile.am along with the other headers (mylib.h) - and the dnl mylib-specific headers can simply use "#include " to dnl obtain the stdint-types. dnl dnl Remember, if the system already had a valid , the dnl generated file will include it directly. No need for fuzzy dnl HAVE_STDINT_H things... dnl dnl (note also the newer variant AX_CREATE_STDINT_H of this macro) dnl dnl @category C dnl @author Guido U. Draheim dnl @version 2003-05-21 dnl @license GPLWithACException AC_DEFUN([AC_CREATE_STDINT_H], [# ------ AC CREATE STDINT H ------------------------------------- AC_MSG_CHECKING([for stdint-types....]) ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` if test "$ac_stdint_h" = "stdint.h" ; then AC_MSG_RESULT("(are you sure you want them in ./stdint.h?)") elif test "$ac_stdint_h" = "inttypes.h" ; then AC_MSG_RESULT("(are you sure you want them in ./inttypes.h?)") else AC_MSG_RESULT("(putting them into $ac_stdint_h)") mkdir -p $(dirname "$ac_stdint_h") fi inttype_headers=`echo inttypes.h sys/inttypes.h sys/inttypes.h $2 \ | sed -e 's/,/ /g'` ac_cv_header_stdint_x="no-file" ac_cv_header_stdint_o="no-file" ac_cv_header_stdint_u="no-file" for i in stdint.h $inttype_headers ; do unset ac_cv_type_uintptr_t unset ac_cv_type_uint64_t _AC_CHECK_TYPE_NEW(uintptr_t,[ac_cv_header_stdint_x=$i],dnl continue,[#include <$i>]) AC_CHECK_TYPE(uint64_t,[and64="(uint64_t too)"],[and64=""],[#include<$i>]) AC_MSG_RESULT(... seen our uintptr_t in $i $and64) break; done if test "$ac_cv_header_stdint_x" = "no-file" ; then for i in stdint.h $inttype_headers ; do unset ac_cv_type_uint32_t unset ac_cv_type_uint64_t AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],dnl continue,[#include <$i>]) AC_CHECK_TYPE(uint64_t,[and64="(uint64_t too)"],[and64=""],[#include<$i>]) AC_MSG_RESULT(... seen our uint32_t in $i $and64) break; done if test "$ac_cv_header_stdint_o" = "no-file" ; then for i in sys/types.h $inttype_headers ; do unset ac_cv_type_u_int32_t unset ac_cv_type_u_int64_t AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],dnl continue,[#include <$i>]) AC_CHECK_TYPE(uint64_t,[and64="(u_int64_t too)"],[and64=""],[#include<$i>]) AC_MSG_RESULT(... seen our u_int32_t in $i $and64) break; done fi fi # ----------------- DONE inttypes.h checks MAYBE C basic types -------- if test "$ac_cv_header_stdint_x" = "no-file" ; then AC_COMPILE_CHECK_SIZEOF(char) AC_COMPILE_CHECK_SIZEOF(short) AC_COMPILE_CHECK_SIZEOF(int) AC_COMPILE_CHECK_SIZEOF(long) AC_COMPILE_CHECK_SIZEOF(void*) ac_cv_header_stdint_test="yes" else ac_cv_header_stdint_test="no" fi # ----------------- DONE inttypes.h checks START header ------------- _ac_stdint_h=AS_TR_CPP(_$ac_stdint_h) AC_MSG_RESULT(creating $ac_stdint_h : $_ac_stdint_h) echo "#ifndef" $_ac_stdint_h >$ac_stdint_h echo "#define" $_ac_stdint_h "1" >>$ac_stdint_h echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint_h echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint_h if test "$GCC" = "yes" ; then echo "/* generated using a gnu compiler version" `$CC --version` "*/" \ >>$ac_stdint_h else echo "/* generated using $CC */" >>$ac_stdint_h fi echo "" >>$ac_stdint_h if test "$ac_cv_header_stdint_x" != "no-file" ; then ac_cv_header_stdint="$ac_cv_header_stdint_x" elif test "$ac_cv_header_stdint_o" != "no-file" ; then ac_cv_header_stdint="$ac_cv_header_stdint_o" elif test "$ac_cv_header_stdint_u" != "no-file" ; then ac_cv_header_stdint="$ac_cv_header_stdint_u" else ac_cv_header_stdint="stddef.h" fi # ----------------- See if int_least and int_fast types are present unset ac_cv_type_int_least32_t unset ac_cv_type_int_fast32_t AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) if test "$ac_cv_header_stdint" != "stddef.h" ; then if test "$ac_cv_header_stdint" != "stdint.h" ; then AC_MSG_RESULT(..adding include stddef.h) echo "#include " >>$ac_stdint_h fi ; fi AC_MSG_RESULT(..adding include $ac_cv_header_stdint) echo "#include <$ac_cv_header_stdint>" >>$ac_stdint_h echo "" >>$ac_stdint_h # ----------------- DONE header START basic int types ------------- if test "$ac_cv_header_stdint_x" = "no-file" ; then AC_MSG_RESULT(... need to look at C basic types) dnl ac_cv_header_stdint_test="yes" # moved up before creating the file else AC_MSG_RESULT(... seen good stdint.h inttypes) dnl ac_cv_header_stdint_test="no" # moved up before creating the file fi if test "$ac_cv_header_stdint_u" != "no-file" ; then AC_MSG_RESULT(... seen bsd/sysv typedefs) cat >>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h < 199901L #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef long long int64_t; typedef unsigned long long uint64_t; #endif #elif !defined __STRICT_ANSI__ #if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #endif #elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ dnl /* note: all ELF-systems seem to have loff-support which needs 64-bit */ #if !defined _NO_LONGLONG #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef long long int64_t; typedef unsigned long long uint64_t; #endif #endif #elif defined __alpha || (defined __mips && defined _ABIN32) #if !defined _NO_LONGLONG #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef long int64_t; typedef unsigned long uint64_t; #endif #endif /* compiler/cpu type ... or just ISO C99 */ #endif #endif EOF # plus a default 64-bit for systems that are likely to be 64-bit ready case "$ac_cv_sizeof_x:$ac_cv_sizeof_voidp:$ac_cv_sizeof_long" in 1:2:8:8) AC_MSG_RESULT(..adding uint64_t default, normal 64-bit system) cat >>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h < dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $ dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) dnl Tries to compile with the given CFLAGS. dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, dnl and ACTION-IF-NOT-ACCEPTED otherwise. AC_DEFUN([AS_COMPILER_FLAG], [ AC_MSG_CHECKING([to see if compiler understands $1]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $1" AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CFLAGS="$save_CFLAGS" if test "X$flag_ok" = Xyes ; then m4_ifvaln([$2],[$2]) true else m4_ifvaln([$3],[$3]) true fi AC_MSG_RESULT([$flag_ok]) ]) dnl AS_COMPILER_FLAGS(VAR, FLAGS) dnl Tries to compile with the given CFLAGS. AC_DEFUN([AS_COMPILER_FLAGS], [ list=$2 flags_supported="" flags_unsupported="" AC_MSG_CHECKING([for supported compiler flags]) for each in $list do save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $each" AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CFLAGS="$save_CFLAGS" if test "X$flag_ok" = Xyes ; then flags_supported="$flags_supported $each" else flags_unsupported="$flags_unsupported $each" fi done AC_MSG_RESULT([$flags_supported]) if test "X$flags_unsupported" != X ; then AC_MSG_WARN([unsupported compiler flags: $flags_unsupported]) fi $1="$$1 $flags_supported" ]) libmongoc-1.3.1/build/autotools/m4/ax_check_compile_flag.m4000066400000000000000000000062511264720626300236610ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS libmongoc-1.3.1/build/autotools/m4/ax_check_link_flag.m4000066400000000000000000000057601264720626300231720ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) # # DESCRIPTION # # Check whether the given FLAG works with the linker or gives an error. # (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the linker's default flags # when the check is done. The check is thus made with the flags: "LDFLAGS # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 AC_DEFUN([AX_CHECK_LINK_FLAG], [AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $4 $1" AC_LINK_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) LDFLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_LINK_FLAGS libmongoc-1.3.1/build/autotools/m4/ax_pthread.m4000066400000000000000000000326761264720626300215440ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # # 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 21 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac # Clang doesn't consider unrecognized options an error unless we specify # -Werror. We throw in some extra Clang-specific options to ensure that # this doesn't happen for GCC, which also accepts -Werror. AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) save_CFLAGS="$CFLAGS" ax_pthread_extra_flags="-Werror" CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], [AC_MSG_RESULT([yes])], [ax_pthread_extra_flags= AC_MSG_RESULT([no])]) CFLAGS="$save_CFLAGS" if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT([$attr_name]) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else # TODO: What about Clang on Solaris? flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT([$flag]) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], [ax_cv_PTHREAD_PRIO_INHERIT], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: compile with *_r variant if test "x$GCC" != xyes; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" AC_SUBST([PTHREAD_LIBS]) AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD libmongoc-1.3.1/build/autotools/m4/pkg.m4000066400000000000000000000162311264720626300201730ustar00rootroot00000000000000# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES # PKG_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable pkgconfigdir as the location where a module # should install pkg-config .pc files. By default the directory is # $libdir/pkgconfig, but the default can be changed by passing # DIRECTORY. The user can override through the --with-pkgconfigdir # parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_INSTALLDIR # PKG_NOARCH_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable noarch_pkgconfigdir as the location where a # module should install arch-independent pkg-config .pc files. By # default the directory is $datadir/pkgconfig, but the default can be # changed by passing DIRECTORY. The user can override through the # --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_NOARCH_INSTALLDIR libmongoc-1.3.1/build/autotools/m4/silent.m4000066400000000000000000000026721264720626300207140ustar00rootroot00000000000000dnl Use GNU make's -s when available dnl dnl Copyright (c) 2010, Damien Lespiau dnl dnl DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE dnl TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION dnl dnl 0. You just DO WHAT THE FUCK YOU WANT TO. dnl dnl The above copyright notice and this permission notice shall be dnl included in all copies or substantial portions of the Software. dnl dnl Simply put this file in your m4 macro directory (as everyone should be dnl using AC_CONFIG_MACRO_DIR by now!) and add AS_AM_REALLY_SILENT somewhere dnl in your configure.ac AC_DEFUN([AS_AM_REALLY_SILENT], [ AC_MSG_CHECKING([whether ${MAKE-make} can be made more silent]) dnl And we even cache that FFS! AC_CACHE_VAL( [as_cv_prog_make_can_be_really_silent], [cat >confstfu.make <<\_WTF SHELL = /bin/sh all: @echo '@@@%%%clutter rocks@@@%%%' _WTF as_cv_prog_make_can_be_really_silent=no case `${MAKE-make} -f confstfu.make -s --no-print-directory 2>/dev/null` in *'@@@%%%clutter rocks@@@%%%'*) test $? = 0 && as_cv_prog_make_can_be_really_silent=yes esac rm -f confstfu.make]) if test $as_cv_prog_make_can_be_really_silent = yes; then AC_MSG_RESULT([yes]) make_flags='`\ if test "x$(AM_DEFAULT_VERBOSITY)" = x0; then \ test -z "$V" -o "x$V" = x0 && echo -s; \ else \ test "x$V" = x0 && echo -s; \ fi`' AC_SUBST([AM_MAKEFLAGS], [$make_flags]) else AC_MSG_RESULT([no]) fi ]) libmongoc-1.3.1/build/autotools/scripts/000077500000000000000000000000001264720626300203145ustar00rootroot00000000000000libmongoc-1.3.1/build/autotools/scripts/wrap-compiler-for-flag-check000077500000000000000000000007661264720626300256020ustar00rootroot00000000000000#!/bin/sh # There is no way to make clang's "argument unused" warning fatal. So when # configure checks for supported flags, it runs $CC, $CXX, $LD via this # wrapper. # # Ideally the search string would also include 'clang: ' but this output might # depend on clang's argv[0]. if out=`"$@" 2>&1`; then echo "$out" if echo "$out" | grep 'warning: argument unused' >/dev/null; then echo "$0: found clang warning" exit 1 else exit 0 fi else code=$? echo "$out" exit $code fi libmongoc-1.3.1/build/autotools/versions.ldscript000066400000000000000000000240741264720626300222520ustar00rootroot00000000000000LIBMONGOC_1.0 { global: mongoc_bulk_operation_delete; mongoc_bulk_operation_delete_one; mongoc_bulk_operation_destroy; mongoc_bulk_operation_execute; mongoc_bulk_operation_insert; mongoc_bulk_operation_new; mongoc_bulk_operation_remove; mongoc_bulk_operation_remove_one; mongoc_bulk_operation_replace_one; mongoc_bulk_operation_set_client; mongoc_bulk_operation_set_collection; mongoc_bulk_operation_set_database; mongoc_bulk_operation_set_hint; mongoc_bulk_operation_set_write_concern; mongoc_bulk_operation_update; mongoc_bulk_operation_update_one; mongoc_cleanup; mongoc_client_command; mongoc_client_command_simple; mongoc_client_destroy; mongoc_client_get_collection; mongoc_client_get_database; mongoc_client_get_database_names; mongoc_client_get_gridfs; mongoc_client_get_max_bson_size; mongoc_client_get_max_message_size; mongoc_client_get_read_prefs; mongoc_client_get_server_status; mongoc_client_get_uri; mongoc_client_get_write_concern; mongoc_client_new; mongoc_client_new_from_uri; mongoc_client_pool_destroy; mongoc_client_pool_new; mongoc_client_pool_pop; mongoc_client_pool_push; mongoc_client_pool_set_ssl_opts; mongoc_client_pool_try_pop; mongoc_client_set_read_prefs; mongoc_client_set_ssl_opts; mongoc_client_set_stream_initiator; mongoc_client_set_write_concern; mongoc_collection_aggregate; mongoc_collection_command; mongoc_collection_command_simple; mongoc_collection_count; mongoc_collection_create_bulk_operation; mongoc_collection_create_index; mongoc_collection_delete; mongoc_collection_destroy; mongoc_collection_drop; mongoc_collection_drop_index; mongoc_collection_ensure_index; mongoc_collection_find; mongoc_collection_find_and_modify; mongoc_collection_get_last_error; mongoc_collection_get_name; mongoc_collection_get_read_prefs; mongoc_collection_get_write_concern; mongoc_collection_insert; mongoc_collection_insert_bulk; mongoc_collection_keys_to_index_string; mongoc_collection_remove; mongoc_collection_rename; mongoc_collection_save; mongoc_collection_set_read_prefs; mongoc_collection_set_write_concern; mongoc_collection_stats; mongoc_collection_update; mongoc_collection_validate; mongoc_cursor_clone; mongoc_cursor_current; mongoc_cursor_destroy; mongoc_cursor_error; mongoc_cursor_get_hint; mongoc_cursor_get_host; mongoc_cursor_is_alive; mongoc_cursor_more; mongoc_cursor_next; mongoc_database_add_user; mongoc_database_command; mongoc_database_command_simple; mongoc_database_create_collection; mongoc_database_destroy; mongoc_database_drop; mongoc_database_get_collection; mongoc_database_get_collection_names; mongoc_database_get_name; mongoc_database_get_read_prefs; mongoc_database_get_write_concern; mongoc_database_has_collection; mongoc_database_remove_all_users; mongoc_database_remove_user; mongoc_database_set_read_prefs; mongoc_database_set_write_concern; mongoc_gridfs_create_file; mongoc_gridfs_create_file_from_stream; mongoc_gridfs_destroy; mongoc_gridfs_drop; mongoc_gridfs_file_destroy; mongoc_gridfs_file_error; mongoc_gridfs_file_get_aliases; mongoc_gridfs_file_get_chunk_size; mongoc_gridfs_file_get_content_type; mongoc_gridfs_file_get_filename; mongoc_gridfs_file_get_id; mongoc_gridfs_file_get_length; mongoc_gridfs_file_get_md5; mongoc_gridfs_file_get_metadata; mongoc_gridfs_file_get_upload_date; mongoc_gridfs_file_list_destroy; mongoc_gridfs_file_list_error; mongoc_gridfs_file_list_next; mongoc_gridfs_file_readv; mongoc_gridfs_file_remove; mongoc_gridfs_file_save; mongoc_gridfs_file_seek; mongoc_gridfs_file_set_aliases; mongoc_gridfs_file_set_content_type; mongoc_gridfs_file_set_filename; mongoc_gridfs_file_set_md5; mongoc_gridfs_file_set_metadata; mongoc_gridfs_file_tell; mongoc_gridfs_file_writev; mongoc_gridfs_find; mongoc_gridfs_find_one; mongoc_gridfs_find_one_by_filename; mongoc_gridfs_get_chunks; mongoc_gridfs_get_files; mongoc_gridfs_remove_by_filename; mongoc_index_opt_get_default; mongoc_index_opt_init; mongoc_init; mongoc_log; mongoc_log_default_handler; mongoc_log_level_str; mongoc_log_set_handler; mongoc_matcher_destroy; mongoc_matcher_match; mongoc_matcher_new; mongoc_read_prefs_add_tag; mongoc_read_prefs_copy; mongoc_read_prefs_destroy; mongoc_read_prefs_get_mode; mongoc_read_prefs_get_tags; mongoc_read_prefs_is_valid; mongoc_read_prefs_new; mongoc_read_prefs_set_mode; mongoc_read_prefs_set_tags; mongoc_socket_accept; mongoc_socket_bind; mongoc_socket_close; mongoc_socket_connect; mongoc_socket_destroy; mongoc_socket_errno; mongoc_socket_getnameinfo; mongoc_socket_getsockname; mongoc_socket_listen; mongoc_socket_new; mongoc_socket_recv; mongoc_socket_send; mongoc_socket_sendv; mongoc_socket_setsockopt; mongoc_ssl_opt_get_default; mongoc_stream_buffered_new; mongoc_stream_close; mongoc_stream_destroy; mongoc_stream_file_get_fd; mongoc_stream_file_new; mongoc_stream_file_new_for_path; mongoc_stream_flush; mongoc_stream_get_base_stream; mongoc_stream_gridfs_new; mongoc_stream_read; mongoc_stream_readv; mongoc_stream_setsockopt; mongoc_stream_socket_get_socket; mongoc_stream_socket_new; mongoc_stream_tls_check_cert; mongoc_stream_tls_do_handshake; mongoc_stream_tls_new; mongoc_stream_write; mongoc_stream_writev; mongoc_uri_copy; mongoc_uri_destroy; mongoc_uri_get_auth_mechanism; mongoc_uri_get_auth_source; mongoc_uri_get_database; mongoc_uri_get_hosts; mongoc_uri_get_options; mongoc_uri_get_password; mongoc_uri_get_read_prefs; mongoc_uri_get_replica_set; mongoc_uri_get_ssl; mongoc_uri_get_string; mongoc_uri_get_username; mongoc_uri_get_write_concern; mongoc_uri_new; mongoc_uri_new_for_host_port; mongoc_uri_unescape; mongoc_write_concern_copy; mongoc_write_concern_destroy; mongoc_write_concern_get_fsync; mongoc_write_concern_get_journal; mongoc_write_concern_get_w; mongoc_write_concern_get_wmajority; mongoc_write_concern_get_wtag; mongoc_write_concern_get_wtimeout; mongoc_write_concern_new; mongoc_write_concern_set_fsync; mongoc_write_concern_set_journal; mongoc_write_concern_set_w; mongoc_write_concern_set_wmajority; mongoc_write_concern_set_wtag; mongoc_write_concern_set_wtimeout; local: *; }; LIBMONGOC_1.1 { global: mongoc_client_find_databases; mongoc_client_kill_cursor; mongoc_collection_count_with_opts; mongoc_collection_find_indexes; mongoc_cursor_get_batch_size; mongoc_cursor_get_id; mongoc_cursor_set_batch_size; mongoc_database_find_collections; mongoc_index_opt_geo_get_default; mongoc_index_opt_geo_init; mongoc_index_opt_wt_get_default; mongoc_index_opt_wt_init; mongoc_rand_add; mongoc_rand_seed; mongoc_rand_status; mongoc_socket_check_closed; mongoc_socket_inet_ntop; mongoc_stream_check_closed; mongoc_stream_write; mongoc_uri_get_credentials; mongoc_uri_get_mechanism_properties; } LIBMONGOC_1.0; LIBMONGOC_1.2 { global: mongoc_client_get_default_database; mongoc_bulk_operation_get_write_concern; mongoc_server_description_destroy; mongoc_server_description_host; mongoc_server_description_id; mongoc_server_description_new_copy; mongoc_stream_failed; mongoc_uri_get_read_prefs_t; mongoc_client_pool_max_size; mongoc_client_pool_min_size; mongoc_get_major_version; mongoc_get_minor_version; mongoc_get_micro_version; mongoc_get_version; mongoc_check_version; } LIBMONGOC_1.1; LIBMONGOC_1.3 { global: mongoc_bulk_operation_set_bypass_document_validation; mongoc_collection_find_and_modify_with_opts; mongoc_client_get_read_concern; mongoc_client_set_read_concern; mongoc_collection_copy; mongoc_collection_get_read_concern; mongoc_collection_set_read_concern; mongoc_cursor_get_max_await_time_ms; mongoc_cursor_set_max_await_time_ms; mongoc_database_copy; mongoc_database_get_read_concern; mongoc_database_set_read_concern; mongoc_find_and_modify_opts_destroy; mongoc_find_and_modify_opts_new; mongoc_find_and_modify_opts_set_bypass_document_validation; mongoc_find_and_modify_opts_set_fields; mongoc_find_and_modify_opts_set_flags; mongoc_find_and_modify_opts_set_sort; mongoc_find_and_modify_opts_set_update; mongoc_read_concern_copy; mongoc_read_concern_destroy; mongoc_read_concern_get_level; mongoc_read_concern_new; mongoc_read_concern_set_level; mongoc_uri_get_read_concern; } LIBMONGOC_1.2; libmongoc-1.3.1/build/cmake/000077500000000000000000000000001264720626300156545ustar00rootroot00000000000000libmongoc-1.3.1/build/cmake/FindBSON.cmake000066400000000000000000000037001264720626300202200ustar00rootroot00000000000000# Read-Only variables: # BSON_FOUND - system has the BSON library # BSON_INCLUDE_DIR - the BSON include directory # BSON_LIBRARIES - The libraries needed to use BSON # BSON_VERSION - This is set to $major.$minor.$revision$path (eg. 0.4.1) if (UNIX) find_package(PkgConfig QUIET) pkg_check_modules(_BSON QUIET libbson-1.0) endif () find_path(BSON_INCLUDE_DIR NAMES libbson-1.0/bson.h HINTS ${BSON_ROOT_DIR} ${_BSON_INCLUDEDIR} PATH_SUFFIXES include ) set(BSON_INCLUDE_DIR "${BSON_INCLUDE_DIR}/libbson-1.0") if(WIN32 AND NOT CYGWIN) if(MSVC) find_library(BSON NAMES "bson-1.0" HINTS ${BSON_ROOT_DIR} PATH_SUFFIXES bin lib ) mark_as_advanced(BSON) set(BSON_LIBRARIES ${BSON} ws2_32) else() # bother supporting this? endif() else() find_library(BSON_LIBRARY NAMES bson-1.0 HINTS ${_BSON_LIBDIR} PATH_SUFFIXES lib ) mark_as_advanced(BSON_LIBRARY) find_package (Threads REQUIRED) set(BSON_LIBRARIES ${BSON_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) endif() if (BSON_INCLUDE_DIR) if (_BSON_VERSION) set(BSON_VERSION "${_BSON_VERSION}") elseif(BSON_INCLUDE_DIR AND EXISTS "${BSON_INCLUDE_DIR}/bson-version.h") file(STRINGS "${BSON_INCLUDE_DIR}/bson-version.h" bson_version_str REGEX "^#define[\t ]+BSON_VERSION[\t ]+\([0-9.]+\)[\t ]+$") string(REGEX REPLACE "^.*BSON_VERSION[\t ]+\([0-9.]+\)[\t ]+$" "\\1" BSON_VERSION "${bson_version_str}") endif () endif () include(FindPackageHandleStandardArgs) if (BSON_VERSION) find_package_handle_standard_args(BSON REQUIRED_VARS BSON_LIBRARIES BSON_INCLUDE_DIR VERSION_VAR BSON_VERSION FAIL_MESSAGE "Could NOT find BSON version" ) else () find_package_handle_standard_args(BSON "Could NOT find BSON uuuurh" BSON_LIBRARIES BSON_INCLUDE_DIR ) endif () mark_as_advanced(BSON_INCLUDE_DIR BSON_LIBRARIES) libmongoc-1.3.1/build/cmake/FindSASL2.cmake000066400000000000000000000024311264720626300203030ustar00rootroot00000000000000include(CheckSymbolExists) message (STATUS "Searching for sasl/sasl.h") find_path ( SASL2_INCLUDE_DIR NAMES sasl/sasl.h PATHS /include /usr/include /usr/local/include /usr/share/include /opt/include c:/sasl/include DOC "Searching for sasl/sasl.h") if (SASL2_INCLUDE_DIR) message (STATUS " Found in ${SASL2_INCLUDE_DIR}") else () message (STATUS " Not found (specify -DCMAKE_INCLUDE_PATH=C:/path/to/sasl/include for SASL support)") endif () message (STATUS "Searching for libsasl2") find_library( SASL2_LIBRARY NAMES sasl2 PATHS /usr/lib /lib /usr/local/lib /usr/share/lib /opt/lib /opt/share/lib /var/lib c:/sasl/lib DOC "Searching for libsasl2") if (SASL2_LIBRARY) message (STATUS " Found ${SASL2_LIBRARY}") else () message (STATUS " Not found (specify -DCMAKE_LIBRARY_PATH=C:/path/to/sasl/lib for SASL support)") endif () if (SASL2_INCLUDE_DIR AND SASL2_LIBRARY) set (SASL2_FOUND 1) check_symbol_exists ( sasl_client_done ${SASL2_INCLUDE_DIR}/sasl/sasl.h MONGOC_HAVE_SASL_CLIENT_DONE) if (MONGOC_HAVE_SASL_CLIENT_DONE) set (MONGOC_HAVE_SASL_CLIENT_DONE 1) else () set (MONGOC_HAVE_SASL_CLIENT_DONE 0) endif () else () set (SASL2_FOUND 0) set (MONGOC_HAVE_SASL_CLIENT_DONE 0) endif () libmongoc-1.3.1/build/cmake/LoadVersion.cmake000066400000000000000000000026771264720626300211170ustar00rootroot00000000000000function(LoadVersion FILEPATH PREFIX) # E.g., "MONGOC_VERSION". string(REPLACE ";" "" VERSION_NAME ${PREFIX} _VERSION) file(STRINGS ${FILEPATH} VERSION_CONTENTS) # A list of version components separated by dots and dashes: "1.3.0-dev" string(REGEX MATCHALL "[^.-]+" VERSION ${VERSION_CONTENTS}) list(GET VERSION 0 MAJOR_VERSION) string(REPLACE ";" "" MAJOR_VERSION_NAME ${PREFIX} _MAJOR_VERSION) set(${MAJOR_VERSION_NAME} ${MAJOR_VERSION} PARENT_SCOPE) list(GET VERSION 1 MINOR_VERSION) string(REPLACE ";" "" MINOR_VERSION_NAME ${PREFIX} _MINOR_VERSION) set(${MINOR_VERSION_NAME} ${MINOR_VERSION} PARENT_SCOPE) list(GET VERSION 2 MICRO_VERSION) string(REPLACE ";" "" MICRO_VERSION_NAME ${PREFIX} _MICRO_VERSION) set(${MICRO_VERSION_NAME} ${MICRO_VERSION} PARENT_SCOPE) string(REPLACE ";" "" PRERELEASE_VERSION_NAME ${PREFIX} _PRERELEASE_VERSION) list(LENGTH VERSION VERSION_LENGTH) if(VERSION_LENGTH GREATER 3) list(GET VERSION 3 PRERELEASE_VERSION) set(${PRERELEASE_VERSION_NAME} ${PRERELEASE_VERSION} PARENT_SCOPE) set(${VERSION_NAME} "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}-${PRERELEASE_VERSION}" PARENT_SCOPE) else() set(${PRERELEASE_VERSION_NAME} "" PARENT_SCOPE) set(${VERSION_NAME} "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}" PARENT_SCOPE) endif() endfunction(LoadVersion) libmongoc-1.3.1/build/cmake/Makefile.am000066400000000000000000000002521264720626300177070ustar00rootroot00000000000000EXTRA_DIST += \ build/cmake/FindSASL2.cmake \ build/cmake/FindBSON.cmake \ build/cmake/LoadVersion.cmake \ build/cmake/libmongoc.def \ build/cmake/libmongoc-ssl.def libmongoc-1.3.1/build/cmake/libmongoc-ssl.def000066400000000000000000000167211264720626300211130ustar00rootroot00000000000000EXPORTS mongoc_bulk_operation_delete mongoc_bulk_operation_delete_one mongoc_bulk_operation_destroy mongoc_bulk_operation_execute mongoc_bulk_operation_get_write_concern mongoc_bulk_operation_insert mongoc_bulk_operation_new mongoc_bulk_operation_remove mongoc_bulk_operation_remove_one mongoc_bulk_operation_replace_one mongoc_bulk_operation_set_bypass_document_validation mongoc_bulk_operation_set_client mongoc_bulk_operation_set_collection mongoc_bulk_operation_set_database mongoc_bulk_operation_set_hint mongoc_bulk_operation_set_write_concern mongoc_bulk_operation_update mongoc_bulk_operation_update_one mongoc_check_version mongoc_cleanup mongoc_client_command mongoc_client_command_simple mongoc_client_destroy mongoc_client_find_databases mongoc_client_get_collection mongoc_client_get_database mongoc_client_get_database_names mongoc_client_get_default_database mongoc_client_get_gridfs mongoc_client_get_max_bson_size mongoc_client_get_max_message_size mongoc_client_get_read_concern mongoc_client_get_read_prefs mongoc_client_get_server_status mongoc_client_get_uri mongoc_client_get_write_concern mongoc_client_kill_cursor mongoc_client_new mongoc_client_new_from_uri mongoc_client_pool_destroy mongoc_client_pool_max_size mongoc_client_pool_min_size mongoc_client_pool_new mongoc_client_pool_pop mongoc_client_pool_push mongoc_client_pool_set_ssl_opts mongoc_client_pool_try_pop mongoc_client_set_read_concern mongoc_client_set_read_prefs mongoc_client_set_ssl_opts mongoc_client_set_stream_initiator mongoc_client_set_write_concern mongoc_collection_aggregate mongoc_collection_command mongoc_collection_command_simple mongoc_collection_copy mongoc_collection_count mongoc_collection_count_with_opts mongoc_collection_create_bulk_operation mongoc_collection_create_index mongoc_collection_delete mongoc_collection_destroy mongoc_collection_drop mongoc_collection_drop_index mongoc_collection_ensure_index mongoc_collection_find mongoc_collection_find_and_modify mongoc_collection_find_and_modify_with_opts mongoc_collection_find_indexes mongoc_collection_get_last_error mongoc_collection_get_name mongoc_collection_get_read_concern mongoc_collection_get_read_prefs mongoc_collection_get_write_concern mongoc_collection_insert mongoc_collection_insert_bulk mongoc_collection_keys_to_index_string mongoc_collection_remove mongoc_collection_rename mongoc_collection_save mongoc_collection_set_read_concern mongoc_collection_set_read_prefs mongoc_collection_set_write_concern mongoc_collection_stats mongoc_collection_update mongoc_collection_validate mongoc_cursor_clone mongoc_cursor_current mongoc_cursor_destroy mongoc_cursor_error mongoc_cursor_get_batch_size mongoc_cursor_get_hint mongoc_cursor_get_host mongoc_cursor_get_id mongoc_cursor_get_max_await_time_ms mongoc_cursor_is_alive mongoc_cursor_more mongoc_cursor_next mongoc_cursor_set_batch_size mongoc_cursor_set_max_await_time_ms mongoc_database_add_user mongoc_database_command mongoc_database_command_simple mongoc_database_copy mongoc_database_create_collection mongoc_database_destroy mongoc_database_drop mongoc_database_find_collections mongoc_database_get_collection mongoc_database_get_collection_names mongoc_database_get_name mongoc_database_get_read_concern mongoc_database_get_read_prefs mongoc_database_get_write_concern mongoc_database_has_collection mongoc_database_remove_all_users mongoc_database_remove_user mongoc_database_set_read_concern mongoc_database_set_read_prefs mongoc_database_set_write_concern mongoc_find_and_modify_opts_destroy mongoc_find_and_modify_opts_new mongoc_find_and_modify_opts_set_bypass_document_validation mongoc_find_and_modify_opts_set_fields mongoc_find_and_modify_opts_set_flags mongoc_find_and_modify_opts_set_sort mongoc_find_and_modify_opts_set_update mongoc_get_major_version mongoc_get_micro_version mongoc_get_minor_version mongoc_get_version mongoc_gridfs_create_file mongoc_gridfs_create_file_from_stream mongoc_gridfs_destroy mongoc_gridfs_drop mongoc_gridfs_file_destroy mongoc_gridfs_file_error mongoc_gridfs_file_get_aliases mongoc_gridfs_file_get_chunk_size mongoc_gridfs_file_get_content_type mongoc_gridfs_file_get_filename mongoc_gridfs_file_get_id mongoc_gridfs_file_get_length mongoc_gridfs_file_get_md5 mongoc_gridfs_file_get_metadata mongoc_gridfs_file_get_upload_date mongoc_gridfs_file_list_destroy mongoc_gridfs_file_list_error mongoc_gridfs_file_list_next mongoc_gridfs_file_readv mongoc_gridfs_file_remove mongoc_gridfs_file_save mongoc_gridfs_file_seek mongoc_gridfs_file_set_aliases mongoc_gridfs_file_set_content_type mongoc_gridfs_file_set_filename mongoc_gridfs_file_set_md5 mongoc_gridfs_file_set_metadata mongoc_gridfs_file_tell mongoc_gridfs_file_writev mongoc_gridfs_find mongoc_gridfs_find_one mongoc_gridfs_find_one_by_filename mongoc_gridfs_get_chunks mongoc_gridfs_get_files mongoc_gridfs_remove_by_filename mongoc_index_opt_geo_get_default mongoc_index_opt_geo_init mongoc_index_opt_get_default mongoc_index_opt_init mongoc_index_opt_wt_get_default mongoc_index_opt_wt_init mongoc_init mongoc_log mongoc_log_default_handler mongoc_log_level_str mongoc_log_set_handler mongoc_matcher_destroy mongoc_matcher_match mongoc_matcher_new mongoc_rand_add mongoc_rand_seed mongoc_rand_status mongoc_read_concern_copy mongoc_read_concern_destroy mongoc_read_concern_get_level mongoc_read_concern_new mongoc_read_concern_set_level mongoc_read_prefs_add_tag mongoc_read_prefs_copy mongoc_read_prefs_destroy mongoc_read_prefs_get_mode mongoc_read_prefs_get_tags mongoc_read_prefs_is_valid mongoc_read_prefs_new mongoc_read_prefs_set_mode mongoc_read_prefs_set_tags mongoc_server_description_destroy mongoc_server_description_host mongoc_server_description_id mongoc_server_description_new_copy mongoc_socket_accept mongoc_socket_bind mongoc_socket_check_closed mongoc_socket_close mongoc_socket_connect mongoc_socket_destroy mongoc_socket_errno mongoc_socket_getnameinfo mongoc_socket_getsockname mongoc_socket_inet_ntop mongoc_socket_listen mongoc_socket_new mongoc_socket_recv mongoc_socket_send mongoc_socket_sendv mongoc_socket_setsockopt mongoc_ssl_opt_get_default mongoc_stream_buffered_new mongoc_stream_check_closed mongoc_stream_close mongoc_stream_destroy mongoc_stream_failed mongoc_stream_file_get_fd mongoc_stream_file_new mongoc_stream_file_new_for_path mongoc_stream_flush mongoc_stream_get_base_stream mongoc_stream_gridfs_new mongoc_stream_read mongoc_stream_readv mongoc_stream_setsockopt mongoc_stream_socket_get_socket mongoc_stream_socket_new mongoc_stream_tls_check_cert mongoc_stream_tls_do_handshake mongoc_stream_tls_new mongoc_stream_write mongoc_stream_write mongoc_stream_writev mongoc_uri_copy mongoc_uri_destroy mongoc_uri_get_auth_mechanism mongoc_uri_get_auth_source mongoc_uri_get_credentials mongoc_uri_get_database mongoc_uri_get_hosts mongoc_uri_get_mechanism_properties mongoc_uri_get_options mongoc_uri_get_password mongoc_uri_get_read_concern mongoc_uri_get_read_prefs mongoc_uri_get_read_prefs_t mongoc_uri_get_replica_set mongoc_uri_get_ssl mongoc_uri_get_string mongoc_uri_get_username mongoc_uri_get_write_concern mongoc_uri_new mongoc_uri_new_for_host_port mongoc_uri_unescape mongoc_write_concern_copy mongoc_write_concern_destroy mongoc_write_concern_get_fsync mongoc_write_concern_get_journal mongoc_write_concern_get_w mongoc_write_concern_get_wmajority mongoc_write_concern_get_wtag mongoc_write_concern_get_wtimeout mongoc_write_concern_new mongoc_write_concern_set_fsync mongoc_write_concern_set_journal mongoc_write_concern_set_w mongoc_write_concern_set_wmajority mongoc_write_concern_set_wtag mongoc_write_concern_set_wtimeout libmongoc-1.3.1/build/cmake/libmongoc.def000066400000000000000000000163651264720626300203200ustar00rootroot00000000000000EXPORTS mongoc_bulk_operation_delete mongoc_bulk_operation_delete_one mongoc_bulk_operation_destroy mongoc_bulk_operation_execute mongoc_bulk_operation_get_write_concern mongoc_bulk_operation_insert mongoc_bulk_operation_new mongoc_bulk_operation_remove mongoc_bulk_operation_remove_one mongoc_bulk_operation_replace_one mongoc_bulk_operation_set_bypass_document_validation mongoc_bulk_operation_set_client mongoc_bulk_operation_set_collection mongoc_bulk_operation_set_database mongoc_bulk_operation_set_hint mongoc_bulk_operation_set_write_concern mongoc_bulk_operation_update mongoc_bulk_operation_update_one mongoc_check_version mongoc_cleanup mongoc_client_command mongoc_client_command_simple mongoc_client_destroy mongoc_client_find_databases mongoc_client_get_collection mongoc_client_get_database mongoc_client_get_database_names mongoc_client_get_default_database mongoc_client_get_gridfs mongoc_client_get_max_bson_size mongoc_client_get_max_message_size mongoc_client_get_read_concern mongoc_client_get_read_prefs mongoc_client_get_server_status mongoc_client_get_uri mongoc_client_get_write_concern mongoc_client_kill_cursor mongoc_client_new mongoc_client_new_from_uri mongoc_client_pool_destroy mongoc_client_pool_max_size mongoc_client_pool_min_size mongoc_client_pool_new mongoc_client_pool_pop mongoc_client_pool_push mongoc_client_pool_try_pop mongoc_client_set_read_concern mongoc_client_set_read_prefs mongoc_client_set_stream_initiator mongoc_client_set_write_concern mongoc_collection_aggregate mongoc_collection_command mongoc_collection_command_simple mongoc_collection_copy mongoc_collection_count mongoc_collection_count_with_opts mongoc_collection_create_bulk_operation mongoc_collection_create_index mongoc_collection_delete mongoc_collection_destroy mongoc_collection_drop mongoc_collection_drop_index mongoc_collection_ensure_index mongoc_collection_find mongoc_collection_find_and_modify mongoc_collection_find_and_modify_with_opts mongoc_collection_find_indexes mongoc_collection_get_last_error mongoc_collection_get_name mongoc_collection_get_read_concern mongoc_collection_get_read_prefs mongoc_collection_get_write_concern mongoc_collection_insert mongoc_collection_insert_bulk mongoc_collection_keys_to_index_string mongoc_collection_remove mongoc_collection_rename mongoc_collection_save mongoc_collection_set_read_concern mongoc_collection_set_read_prefs mongoc_collection_set_write_concern mongoc_collection_stats mongoc_collection_update mongoc_collection_validate mongoc_cursor_clone mongoc_cursor_current mongoc_cursor_destroy mongoc_cursor_error mongoc_cursor_get_batch_size mongoc_cursor_get_hint mongoc_cursor_get_host mongoc_cursor_get_id mongoc_cursor_get_max_await_time_ms mongoc_cursor_is_alive mongoc_cursor_more mongoc_cursor_next mongoc_cursor_set_batch_size mongoc_cursor_set_max_await_time_ms mongoc_database_add_user mongoc_database_command mongoc_database_command_simple mongoc_database_copy mongoc_database_create_collection mongoc_database_destroy mongoc_database_drop mongoc_database_find_collections mongoc_database_get_collection mongoc_database_get_collection_names mongoc_database_get_name mongoc_database_get_read_concern mongoc_database_get_read_prefs mongoc_database_get_write_concern mongoc_database_has_collection mongoc_database_remove_all_users mongoc_database_remove_user mongoc_database_set_read_concern mongoc_database_set_read_prefs mongoc_database_set_write_concern mongoc_find_and_modify_opts_destroy mongoc_find_and_modify_opts_new mongoc_find_and_modify_opts_set_bypass_document_validation mongoc_find_and_modify_opts_set_fields mongoc_find_and_modify_opts_set_flags mongoc_find_and_modify_opts_set_sort mongoc_find_and_modify_opts_set_update mongoc_get_major_version mongoc_get_micro_version mongoc_get_minor_version mongoc_get_version mongoc_gridfs_create_file mongoc_gridfs_create_file_from_stream mongoc_gridfs_destroy mongoc_gridfs_drop mongoc_gridfs_file_destroy mongoc_gridfs_file_error mongoc_gridfs_file_get_aliases mongoc_gridfs_file_get_chunk_size mongoc_gridfs_file_get_content_type mongoc_gridfs_file_get_filename mongoc_gridfs_file_get_id mongoc_gridfs_file_get_length mongoc_gridfs_file_get_md5 mongoc_gridfs_file_get_metadata mongoc_gridfs_file_get_upload_date mongoc_gridfs_file_list_destroy mongoc_gridfs_file_list_error mongoc_gridfs_file_list_next mongoc_gridfs_file_readv mongoc_gridfs_file_remove mongoc_gridfs_file_save mongoc_gridfs_file_seek mongoc_gridfs_file_set_aliases mongoc_gridfs_file_set_content_type mongoc_gridfs_file_set_filename mongoc_gridfs_file_set_md5 mongoc_gridfs_file_set_metadata mongoc_gridfs_file_tell mongoc_gridfs_file_writev mongoc_gridfs_find mongoc_gridfs_find_one mongoc_gridfs_find_one_by_filename mongoc_gridfs_get_chunks mongoc_gridfs_get_files mongoc_gridfs_remove_by_filename mongoc_index_opt_geo_get_default mongoc_index_opt_geo_init mongoc_index_opt_get_default mongoc_index_opt_init mongoc_index_opt_wt_get_default mongoc_index_opt_wt_init mongoc_init mongoc_log mongoc_log_default_handler mongoc_log_level_str mongoc_log_set_handler mongoc_matcher_destroy mongoc_matcher_match mongoc_matcher_new mongoc_read_concern_copy mongoc_read_concern_destroy mongoc_read_concern_get_level mongoc_read_concern_new mongoc_read_concern_set_level mongoc_read_prefs_add_tag mongoc_read_prefs_copy mongoc_read_prefs_destroy mongoc_read_prefs_get_mode mongoc_read_prefs_get_tags mongoc_read_prefs_is_valid mongoc_read_prefs_new mongoc_read_prefs_set_mode mongoc_read_prefs_set_tags mongoc_server_description_destroy mongoc_server_description_host mongoc_server_description_id mongoc_server_description_new_copy mongoc_socket_accept mongoc_socket_bind mongoc_socket_check_closed mongoc_socket_close mongoc_socket_connect mongoc_socket_destroy mongoc_socket_errno mongoc_socket_getnameinfo mongoc_socket_getsockname mongoc_socket_inet_ntop mongoc_socket_listen mongoc_socket_new mongoc_socket_recv mongoc_socket_send mongoc_socket_sendv mongoc_socket_setsockopt mongoc_stream_buffered_new mongoc_stream_check_closed mongoc_stream_close mongoc_stream_destroy mongoc_stream_failed mongoc_stream_file_get_fd mongoc_stream_file_new mongoc_stream_file_new_for_path mongoc_stream_flush mongoc_stream_get_base_stream mongoc_stream_gridfs_new mongoc_stream_read mongoc_stream_readv mongoc_stream_setsockopt mongoc_stream_socket_get_socket mongoc_stream_socket_new mongoc_stream_write mongoc_stream_write mongoc_stream_writev mongoc_uri_copy mongoc_uri_destroy mongoc_uri_get_auth_mechanism mongoc_uri_get_auth_source mongoc_uri_get_credentials mongoc_uri_get_database mongoc_uri_get_hosts mongoc_uri_get_mechanism_properties mongoc_uri_get_options mongoc_uri_get_password mongoc_uri_get_read_concern mongoc_uri_get_read_prefs mongoc_uri_get_read_prefs_t mongoc_uri_get_replica_set mongoc_uri_get_ssl mongoc_uri_get_string mongoc_uri_get_username mongoc_uri_get_write_concern mongoc_uri_new mongoc_uri_new_for_host_port mongoc_uri_unescape mongoc_write_concern_copy mongoc_write_concern_destroy mongoc_write_concern_get_fsync mongoc_write_concern_get_journal mongoc_write_concern_get_w mongoc_write_concern_get_wmajority mongoc_write_concern_get_wtag mongoc_write_concern_get_wtimeout mongoc_write_concern_new mongoc_write_concern_set_fsync mongoc_write_concern_set_journal mongoc_write_concern_set_w mongoc_write_concern_set_wmajority mongoc_write_concern_set_wtag mongoc_write_concern_set_wtimeout libmongoc-1.3.1/build/future_function_templates/000077500000000000000000000000001264720626300220715ustar00rootroot00000000000000libmongoc-1.3.1/build/future_function_templates/future-functions.c.template000066400000000000000000000035411264720626300273720ustar00rootroot00000000000000{{ header_comment }} /* * Define two sets of functions: background functions and future functions. * A background function like background_mongoc_cursor_next runs a driver * operation on a thread. * A future function like future_mongoc_cursor_next launches the background * operation and returns a future_t that will resolve when the operation * finishes. * * These are used with mock_server_t so you can run the driver on a thread while * controlling the server from the main thread. */ #include "mongoc-topology-private.h" #include "future-functions.h" {% for F in future_functions %} static void * background_{{ F.name }} (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_{{ F.ret_type }}_type; {% if F.ret_type == 'void' %} {{ F.name }} ({% for P in F.params %} future_value_get_{{ P.type_name }} (future_get_param (future, {{ loop.index0 }})){% if not loop.last %},{% endif %}{% endfor %}); {% else %} future_value_set_{{ F.ret_type }} ( &return_value, {{ F.name }} ({% for P in F.params %} future_value_get_{{ P.type_name }} (future_get_param (future, {{ loop.index0 }})){% if not loop.last %},{% endif %}{% endfor %} )); {% endif %} future_resolve (future, return_value); return NULL; } {% endfor %} {% for F in future_functions %} future_t * {{ F|future_function_name }} ({% for P in F.params %} {{ P.type_name }} {{ P.name }}{% if not loop.last %},{% endif %}{% endfor %}) { future_t *future = future_new (future_value_{{ F.ret_type }}_type, {{ F.params | length }}); {% for P in F.params %} future_value_set_{{ P.type_name }} ( future_get_param (future, {{ loop.index0 }}), {{ P.name }}); {% endfor %} future_start (future, background_{{ F.name }}); return future; } {% endfor %} libmongoc-1.3.1/build/future_function_templates/future-functions.h.template000066400000000000000000000006031264720626300273730ustar00rootroot00000000000000#ifndef FUTURE_FUNCTIONS_H #define FUTURE_FUNCTIONS_H #include "future-value.h" #include "future.h" #include "mongoc-bulk-operation.h" {{ header_comment }} {% for F in future_functions %} future_t * {{ F|future_function_name }} ( {% for P in F.params %} {{ P.type_name }} {{ P.name }}{% if not loop.last %},{% endif %}{% endfor %} ); {% endfor %} #endif /* FUTURE_FUNCTIONS_H */ libmongoc-1.3.1/build/future_function_templates/future-value.c.template000066400000000000000000000013771264720626300265030ustar00rootroot00000000000000#include "future-value.h" {{ header_comment }} future_value_t * future_value_new () { return (future_value_t *) bson_malloc0 (sizeof (future_value_t)); } void future_value_set_void (future_value_t *future_value) { future_value->type = future_value_void_type; } void future_value_get_void (future_value_t *future_value) { assert (future_value->type == future_value_void_type); } {% for T in type_list %} void future_value_set_{{ T }}(future_value_t *future_value, {{ T }} value) { future_value->type = future_value_{{ T }}_type; future_value->{{ T }}_value = value; } {{ T }} future_value_get_{{ T }} (future_value_t *future_value) { assert (future_value->type == future_value_{{ T }}_type); return future_value->{{ T }}_value; } {% endfor %} libmongoc-1.3.1/build/future_function_templates/future-value.h.template000066400000000000000000000021711264720626300265010ustar00rootroot00000000000000#ifndef FUTURE_VALUE_H #define FUTURE_VALUE_H #include #include #include "mongoc-server-description.h" #include "mongoc-topology-private.h" {{ header_comment }} {% for T in typedef_list %}{% if T.typedef %} typedef {{ T.typedef }} {{ T.name }};{% endif %}{% endfor %} typedef enum { future_value_no_type = 0, {% for T in type_list_with_void %} future_value_{{ T }}_type, {% endfor %} } future_value_type_t; typedef struct _future_value_t { future_value_type_t type; union { {% for T in type_list %} {{ T }} {{ T }}_value; {% endfor %} }; } future_value_t; future_value_t *future_value_new (); #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" #endif void future_value_set_void (future_value_t *future_value); void future_value_get_void (future_value_t *future_value); {% for T in type_list %} void future_value_set_{{ T }}( future_value_t *future_value, {{ T }} value); {{ T }} future_value_get_{{ T }} ( future_value_t *future_value); {% endfor %} #ifdef __clang__ #pragma clang diagnostic pop #endif #endif /* FUTURE_VALUE_H */ libmongoc-1.3.1/build/future_function_templates/future.c.template000066400000000000000000000052431264720626300253650ustar00rootroot00000000000000#include #include "mongoc-array-private.h" #include "mongoc-thread-private.h" #include "future.h" #include "../test-libmongoc.h" {{ header_comment }} #define DEFAULT_FUTURE_TIMEOUT_MS 10 * 1000 static int64_t get_future_timeout_ms () { return test_framework_getenv_int64 ("MONGOC_TEST_FUTURE_TIMEOUT_MS", DEFAULT_FUTURE_TIMEOUT_MS); } void future_get_void (future_t *future) { if (!future_wait (future)) { fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } } {% for T in type_list %} {{ T }} future_get_{{ T }} (future_t *future) { if (future_wait (future)) { return future_value_get_{{ T }} (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } {% endfor %} future_t * future_new (future_value_type_t return_type, int argc) { future_t *future; future = (future_t *)bson_malloc0 (sizeof *future); future->return_value.type = return_type; future->argc = argc; future->argv = (future_value_t *)bson_malloc0 ((size_t) argc * sizeof(future_value_t)); mongoc_cond_init (&future->cond); mongoc_mutex_init (&future->mutex); return future; } future_value_t * future_get_param (future_t *future, int i) { return &future->argv[i]; } void future_start (future_t *future, void *(*start_routine)(void *)) { int r = mongoc_thread_create (&future->thread, start_routine, (void *) future); assert (!r); } void future_resolve (future_t *future, future_value_t return_value) { mongoc_mutex_lock (&future->mutex); assert (!future->resolved); assert (future->return_value.type == return_value.type); future->return_value = return_value; future->resolved = true; mongoc_cond_signal (&future->cond); mongoc_mutex_unlock (&future->mutex); } bool future_wait (future_t *future) { int64_t deadline = bson_get_monotonic_time () + get_future_timeout_ms (); bool resolved; mongoc_mutex_lock (&future->mutex); while (!future->resolved && bson_get_monotonic_time () <= deadline) { mongoc_cond_timedwait (&future->cond, &future->mutex, get_future_timeout_ms ()); } resolved = future->resolved; mongoc_mutex_unlock (&future->mutex); if (resolved) { future->awaited = true; /* free memory */ mongoc_thread_join (future->thread); } return resolved; } void future_destroy (future_t *future) { assert (future->awaited); bson_free (future->argv); mongoc_cond_destroy (&future->cond); mongoc_mutex_destroy (&future->mutex); bson_free (future); } libmongoc-1.3.1/build/future_function_templates/future.h.template000066400000000000000000000016171264720626300253730ustar00rootroot00000000000000#ifndef FUTURE_H #define FUTURE_H #include #include "future-value.h" #include "mongoc-thread-private.h" {{ header_comment }} typedef struct { bool resolved; bool awaited; future_value_t return_value; int argc; future_value_t *argv; mongoc_cond_t cond; mongoc_mutex_t mutex; mongoc_thread_t thread; } future_t; future_t *future_new (future_value_type_t return_type, int argc); future_value_t *future_get_param (future_t *future, int i); void future_start (future_t *future, void *(*start_routine)(void *)); void future_resolve (future_t *future, future_value_t return_value); bool future_wait (future_t *future); void future_get_void (future_t *future); {% for T in type_list %} {{ T }} future_get_{{ T }} (future_t *future); {% endfor %} void future_destroy (future_t *future); #endif /* FUTURE_H */ libmongoc-1.3.1/build/generate-future-functions.py000066400000000000000000000261551264720626300222670ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2015 MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Generate test functions for use with mock_server_t. Defines functions like future_cursor_next in future-functions.h and future-functions.c, which defer a libmongoc operation to a background thread via functions like background_cursor_next. Also defines functions like future_value_set_bson_ptr and future_value_get_bson_ptr which support the future / background functions, and functions like future_get_bson_ptr which wait for a future to resolve, then return its value. These future functions are used in conjunction with mock_server_t to conveniently test libmongoc wire protocol operations. Written for Python 2.6+, requires Jinja 2 for templating. """ import glob from collections import namedtuple from os.path import basename, dirname, join as joinpath, normpath from jinja2 import Environment, FileSystemLoader # Please "pip install jinja2". this_dir = dirname(__file__) template_dir = joinpath(this_dir, 'future_function_templates') mock_server_dir = normpath(joinpath(this_dir, '../tests/mock_server')) # Add additional types here. Use typedefs for derived types so they can # be named with one symbol. typedef = namedtuple("typedef", ["name", "typedef"]) # These are typedef'ed if necessary in future-value.h, and added to the union # of possible future_value_t.value types. future_value_t getters and setters # are generated for all types, as well as future_t getters. typedef_list = [ # Fundamental. typedef("bool", None), typedef("char_ptr", "char *"), typedef("char_ptr_ptr", "char **"), typedef("int", None), typedef("int64_t", None), typedef("size_t", None), typedef("ssize_t", None), typedef("uint32_t", None), # Const fundamental. typedef("const_char_ptr", "const char *"), # libbson. typedef("bson_error_ptr", "bson_error_t *"), typedef("bson_ptr", "bson_t *"), # Const libbson. typedef("const_bson_ptr", "const bson_t *"), typedef("const_bson_ptr_ptr", "const bson_t **"), # libmongoc. typedef("mongoc_bulk_operation_ptr", "mongoc_bulk_operation_t *"), typedef("mongoc_client_ptr", "mongoc_client_t *"), typedef("mongoc_collection_ptr", "mongoc_collection_t *"), typedef("mongoc_cursor_ptr", "mongoc_cursor_t *"), typedef("mongoc_database_ptr", "mongoc_database_t *"), typedef("mongoc_gridfs_file_ptr", "mongoc_gridfs_file_t *"), typedef("mongoc_gridfs_ptr", "mongoc_gridfs_t *"), typedef("mongoc_insert_flags_t", None), typedef("mongoc_iovec_ptr", "mongoc_iovec_t *"), typedef("mongoc_query_flags_t", None), typedef("mongoc_server_description_ptr", "mongoc_server_description_t *"), typedef("mongoc_ss_optype_t", None), typedef("mongoc_topology_ptr", "mongoc_topology_t *"), # Const libmongoc. typedef("const_mongoc_find_and_modify_opts_ptr", "const mongoc_find_and_modify_opts_t *"), typedef("const_mongoc_read_prefs_ptr", "const mongoc_read_prefs_t *"), typedef("const_mongoc_write_concern_ptr", "const mongoc_write_concern_t *"), ] type_list = [T.name for T in typedef_list] type_list_with_void = type_list + ['void'] param = namedtuple("param", ["type_name", "name"]) future_function = namedtuple("future_function", ["ret_type", "name", "params"]) # Add additional functions to be tested here. For a name like "cursor_next", we # generate two functions: future_cursor_next to prepare the future_t and launch # a background thread, and background_cursor_next to run on the thread and # resolve the future. future_functions = [ future_function("uint32_t", "mongoc_bulk_operation_execute", [param("mongoc_bulk_operation_ptr", "bulk"), param("bson_ptr", "reply"), param("bson_error_ptr", "error")]), future_function("bool", "mongoc_client_command_simple", [param("mongoc_client_ptr", "client"), param("const_char_ptr", "db_name"), param("const_bson_ptr", "command"), param("const_mongoc_read_prefs_ptr", "read_prefs"), param("bson_ptr", "reply"), param("bson_error_ptr", "error")]), future_function("void", "mongoc_client_kill_cursor", [param("mongoc_client_ptr", "client"), param("int64_t", "cursor_id")]), future_function("mongoc_cursor_ptr", "mongoc_collection_aggregate", [param("mongoc_collection_ptr", "collection"), param("mongoc_query_flags_t", "flags"), param("const_bson_ptr", "pipeline"), param("const_bson_ptr", "options"), param("const_mongoc_read_prefs_ptr", "read_prefs")]), future_function("int64_t", "mongoc_collection_count", [param("mongoc_collection_ptr", "collection"), param("mongoc_query_flags_t", "flags"), param("const_bson_ptr", "query"), param("int64_t", "skip"), param("int64_t", "limit"), param("const_mongoc_read_prefs_ptr", "read_prefs"), param("bson_error_ptr", "error")]), future_function("bool", "mongoc_collection_find_and_modify_with_opts", [param("mongoc_collection_ptr", "collection"), param("const_bson_ptr", "query"), param("const_mongoc_find_and_modify_opts_ptr", "opts"), param("bson_ptr", "reply"), param("bson_error_ptr", "error")]), future_function("bool", "mongoc_collection_find_and_modify", [param("mongoc_collection_ptr", "collection"), param("const_bson_ptr", "query"), param("const_bson_ptr", "sort"), param("const_bson_ptr", "update"), param("const_bson_ptr", "fields"), param("bool", "_remove"), param("bool", "upsert"), param("bool", "_new"), param("bson_ptr", "reply"), param("bson_error_ptr", "error")]), future_function("bool", "mongoc_collection_insert", [param("mongoc_collection_ptr", "collection"), param("mongoc_insert_flags_t", "flags"), param("const_bson_ptr", "document"), param("const_mongoc_write_concern_ptr", "write_concern"), param("bson_error_ptr", "error")]), future_function("bool", "mongoc_collection_insert_bulk", [param("mongoc_collection_ptr", "collection"), param("mongoc_insert_flags_t", "flags"), param("const_bson_ptr_ptr", "documents"), param("uint32_t", "n_documents"), param("const_mongoc_write_concern_ptr", "write_concern"), param("bson_error_ptr", "error")]), future_function("void", "mongoc_cursor_destroy", [param("mongoc_cursor_ptr", "cursor")]), future_function("bool", "mongoc_cursor_next", [param("mongoc_cursor_ptr", "cursor"), param("const_bson_ptr_ptr", "doc")]), future_function("char_ptr_ptr", "mongoc_client_get_database_names", [param("mongoc_client_ptr", "client"), param("bson_error_ptr", "error")]), future_function("char_ptr_ptr", "mongoc_database_get_collection_names", [param("mongoc_database_ptr", "database"), param("bson_error_ptr", "error")]), future_function("ssize_t", "mongoc_gridfs_file_readv", [param("mongoc_gridfs_file_ptr", "file"), param("mongoc_iovec_ptr", "iov"), param("size_t", "iovcnt"), param("size_t", "min_bytes"), param("uint32_t", "timeout_msec")]), future_function("int", "mongoc_gridfs_file_seek", [param("mongoc_gridfs_file_ptr", "file"), param("int64_t", "delta"), param("int", "whence")]), future_function("ssize_t", "mongoc_gridfs_file_writev", [param("mongoc_gridfs_file_ptr", "file"), param("mongoc_iovec_ptr", "iov"), param("size_t", "iovcnt"), param("uint32_t", "timeout_msec")]), future_function("mongoc_server_description_ptr", "mongoc_topology_select", [param("mongoc_topology_ptr", "topology"), param("mongoc_ss_optype_t", "optype"), param("const_mongoc_read_prefs_ptr", "read_prefs"), param("int64_t", "local_threshold_ms"), param("bson_error_ptr", "error")]), future_function("mongoc_gridfs_ptr", "mongoc_client_get_gridfs", [param("mongoc_client_ptr", "client"), param("const_char_ptr", "db"), param("const_char_ptr", "prefix"), param("bson_error_ptr", "error")]), ] for fn in future_functions: if fn.ret_type not in type_list_with_void: raise Exception('bad type "%s"\n\nin %s' % (fn.ret_type, fn)) for p in fn.params: if p.type_name not in type_list: raise Exception('bad type "%s"\n\nin %s' % (p.type_name, fn)) header_comment = """/************************************************** * * Generated by build/%s. * * DO NOT EDIT THIS FILE. * *************************************************/""" % basename(__file__) def future_function_name(fn): if fn.name.startswith('mongoc'): # E.g. future_cursor_next(). return 'future' + fn.name[len('mongoc'):] else: # E.g. future__mongoc_client_kill_cursor(). return 'future_' + fn.name env = Environment(loader=FileSystemLoader(template_dir)) env.filters['future_function_name'] = future_function_name files = ["future.h", "future.c", "future-value.h", "future-value.c", "future-functions.h", "future-functions.c"] for file_name in files: print(file_name) with open(joinpath(mock_server_dir, file_name), 'w+') as f: t = env.get_template(file_name + ".template") f.write(t.render(globals())) libmongoc-1.3.1/build/libbson.xsl000066400000000000000000000014231264720626300167540ustar00rootroot00000000000000 http://api.mongodb.org/libbson/current/ .html libmongoc-1.3.1/build/rpm/000077500000000000000000000000001264720626300153725ustar00rootroot00000000000000libmongoc-1.3.1/build/rpm/mongo-c-driver.spec000066400000000000000000000172631264720626300211070ustar00rootroot00000000000000# norootforbuild %define DriverName mongo-c-driver %define DriverVersion 1.2.1 %define BsonName libbson %define BsonVersion 1.2.1 Name: %{DriverName} Version: %{DriverVersion} Release: 1%{?dist} Summary: MongoDB C Driver Group: System Environment/Libraries License: ASL 2.0 URL: https://github.com/mongodb/mongo-c-driver Source0: https://github.com/mongodb/mongo-c-driver/releases/download/%{DriverVersion}/mongo-c-driver-%{DriverVersion}.tar.gz BuildRequires: autoconf BuildRequires: automake BuildRequires: libtool BuildRequires: cyrus-sasl-devel BuildRequires: openssl-devel BuildRequires: pkgconfig %description mongo-c-driver is a library for building high-performance applications that communicate with the MongoDB NoSQL database in the C language. %package devel Summary: Development files for mongo-c-driver Requires: %{DriverName}%{?_isa} = %{DriverVersion}-%{release} Group: Development/Libraries %description devel The %{DriverName}-devel package contains libraries and header files for developing applications that use %{DriverName}. %package -n %{BsonName} Summary: A library for parsing and generating BSON documents. Version: %{BsonVersion} Group: System Environment/Libraries %description -n %{BsonName} Libbson is a library providing useful routines related to building, parsing, and iterating BSON documents. It is a useful base for those wanting to write high-performance C extensions to higher level languages such as Python, Ruby, or Perl. %package -n %{BsonName}-devel Summary: Development files for libbson Requires: %{BsonName}%{?_isa} = %{BsonVersion}-%{release} Version: %{BsonVersion} Group: Development/Libraries %description -n %{BsonName}-devel The %{BsonName}-devel package contains libraries and header files for developing applications that use %{BsonName}. %prep %setup -q -n %{DriverName}-%{DriverVersion} automake %build %configure --disable-static --disable-silent-rules --enable-debug-symbols --enable-man-pages --enable-ssl --enable-sasl --with-libbson=bundled--enable-optimizations make %{?_smp_mflags} %check make local-check make abicheck %install %makeinstall find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %{_prefix}/share/doc/mongo-c-driver/* %{_libdir}/libmongoc-1.0.so.* %{_libdir}/libmongoc-priv.so* %files -n %{BsonName} %{_prefix}/share/doc/libbson/* %{_libdir}/libbson-1.0.so.* %files devel %dir %{_includedir}/libmongoc-1.0 %{_includedir}/libmongoc-1.0/*.h %{_includedir}/libmongoc-1.0/*.def %{_includedir}/libmongoc-1.0/*.defs %{_libdir}/libmongoc-1.0.so %{_libdir}/pkgconfig/libmongoc-priv.pc %{_libdir}/pkgconfig/libmongoc-1.0.pc %{_libdir}/pkgconfig/libmongoc-ssl-1.0.pc %{_bindir}/mongoc-stat %{_prefix}/share/man/man3/mongoc* %files -n %{BsonName}-devel %dir %{_includedir}/libbson-1.0 %{_includedir}/libbson-1.0/*.h %{_libdir}/libbson-1.0.so %{_libdir}/pkgconfig/libbson-1.0.pc %{_prefix}/share/man/man3/bson* %changelog -n %{DriverName} * Thu Oct 29 2015 A. Jesse Jiryu Davis - 1.2.1-1 - Release 1.2.1 * Tue Oct 13 2015 A. Jesse Jiryu Davis - 1.2.0-1 - Release 1.2.0 * Wed Sep 23 2015 A. Jesse Jiryu Davis - 1.1.11-1 - Release 1.1.11 * Tue Jul 21 2015 A. Jesse Jiryu Davis - 1.1.10-1 - Release 1.1.10 * Sun Jun 28 2015 A. Jesse Jiryu Davis - 1.1.9-1 - Release 1.1.9 * Sun Jun 21 2015 A. Jesse Jiryu Davis - 1.1.8-1 - Release 1.1.8 * Tue Jun 9 2015 A. Jesse Jiryu Davis - 1.1.7-1 - Release 1.1.7 * Tue May 18 2015 A. Jesse Jiryu Davis - 1.1.6-1 - Release 1.1.6 * Tue May 12 2015 A. Jesse Jiryu Davis - 1.1.5-1 - Release 1.1.5 * Wed Apr 1 2015 Jason Carey - 1.1.4-1 - Release 1.1.4. * Tue Mar 10 2015 Jason Carey - 1.1.3-1 - Post-release bump for 1.1.2 * Tue Mar 10 2015 Jason Carey - 1.1.2-1 - Release 1.1.2. * Wed Jan 28 2015 Jason Carey - 1.1.1-1 - Post-release bump for 1.1.0 * Wed Jan 28 2015 Jason Carey - 1.1.0-1 - Release 1.1.0. * Thu Nov 13 2014 Jason Carey - 1.1.0-rc0-1 - Release 1.1.0-rc0. * Thu Oct 09 2014 Jason Carey - 1.0.3-1 - Post-release bump for 1.0.3. * Thu Oct 09 2014 Jason Carey - 1.0.2-1 - Release 1.0.2. * Tue Aug 26 2014 Christian Hergert - 1.0.0-1 - Post-release bump for 1.0.1. * Tue Aug 26 2014 Christian Hergert - 1.0.0-1 - Release 1.0.0. * Tue Aug 13 2014 Christian Hergert - 0.98.2-1 - Bump for 0.98.2. * Tue Jul 17 2014 Christian Hergert - 0.98.1-1 - Bump for development release. * Tue Jul 16 2014 Christian Hergert - 0.98.0-1 - Bump for 0.98.0. * Tue Jun 20 2014 Christian Hergert - 0.96.5-1 - Bump for development releases. * Tue Jun 20 2014 Christian Hergert - 0.96.4-1 - Release of 0.96.4 * Tue Jun 10 2014 Christian Hergert - 0.96.3-1 - Enable automated builds of 0.96.3 * Thu Jun 05 2014 Christian Hergert - 0.96.2-1 - Release 0.96.2 * Fri May 30 2014 Christian Hergert - 0.96.0-1 - Release 0.96.0 * Tue May 06 2014 Christian Hergert - 0.94.3-1 - Initial package %changelog -n %{BsonName} * Thu Oct 29 2015 A. Jesse Jiryu Davis - 1.2.1-1 - Release 1.2.1 * Tue Oct 13 2015 A. Jesse Jiryu Davis - 1.2.0-1 - Release 1.2.0 * Wed Sep 23 2015 A. Jesse Jiryu Davis - 1.1.11-1 - Release 1.1.11 * Tue Jul 21 2015 A. Jesse Jiryu Davis - 1.1.10-1 - Release 1.1.10 * Sun Jun 28 2015 A. Jesse Jiryu Davis - 1.1.9-1 - Release 1.1.9 * Sun Jun 21 2015 A. Jesse Jiryu Davis - 1.1.8-1 - Release 1.1.8 * Tue Jun 9 2015 A. Jesse Jiryu Davis - 1.1.7-1 - Release 1.1.7 * Tue May 18 2015 A. Jesse Jiryu Davis - 1.1.6-1 - Release 1.1.6 * Tue May 12 2015 A. Jesse Jiryu Davis - 1.1.5-1 - Release 1.1.5 * Wed Apr 1 2015 Jason Carey - 1.1.4-1 - Release 1.1.4. * Tue Mar 10 2015 Jason Carey - 1.1.3-1 - Post-release bump for 1.1.2 * Tue Mar 10 2015 Jason Carey - 1.1.2-1 - Release 1.1.2. * Wed Jan 28 2015 Jason Carey - 1.1.1-1 - Post-release bump for 1.1.0 * Wed Jan 28 2015 Jason Carey - 1.1.0-1 - Release 1.1.0. * Thu Nov 13 2014 Jason Carey - 1.1.0-rc0-1 - Release 1.1.0-rc0. * Thu Oct 09 2014 Jason Carey - 1.0.3-1 - Post-release bump for 1.0.3. * Thu Oct 09 2014 Jason Carey - 1.0.2-1 - Release 1.0.2. * Tue Aug 26 2014 Christian Hergert - 1.0.0-1 - Post-releases bump for 1.0.1. * Tue Aug 26 2014 Christian Hergert - 1.0.0-1 - Release 1.0.0. * Tue Jul 16 2014 Christian Hergert - 0.98.0-1 - Bump for 0.98.0. * Tue Jun 20 2014 Christian Hergert - 0.8.5-1 - Bump for development releases. * Tue Jun 20 2014 Christian Hergert - 0.8.4-1 - Release of 0.8.4 * Tue Jun 10 2014 Christian Hergert - 0.8.3-1 - Enable automated builds of 0.8.3 libmongoc-1.3.1/build/version.in000066400000000000000000000000211264720626300166020ustar00rootroot00000000000000@MONGOC_VERSION@ libmongoc-1.3.1/configure.ac000066400000000000000000000033131264720626300157630ustar00rootroot00000000000000AC_PREREQ(2.60) # Set version from contents of "VERSION_CURRENT" file. AC_INIT([mongo-c-driver], m4_esyscmd_s(cat VERSION_CURRENT), [https://jira.mongodb.org/browse/CDRIVER]) m4_include([build/autotools/Versions.m4]) AC_CONFIG_MACRO_DIR([build/autotools/m4]) AC_CONFIG_AUX_DIR([build/autotools]) AC_SUBST(ACLOCAL_AMFLAGS, "-I build/autotools") MONGOC_API_VERSION=1.0 AC_SUBST(MONGOC_API_VERSION) m4_include([build/autotools/CheckCompiler.m4]) m4_include([build/autotools/CheckProgs.m4]) m4_include([build/autotools/CheckHost.m4]) m4_include([build/autotools/CheckTarget.m4]) m4_include([build/autotools/SetupLibtool.m4]) LT_INIT m4_include([build/autotools/ReadCommandLineArguments.m4]) m4_include([build/autotools/CheckSasl.m4]) m4_include([build/autotools/CheckSSL.m4]) m4_include([build/autotools/FindDependencies.m4]) m4_include([build/autotools/AutoHarden.m4]) m4_include([build/autotools/PlatformFlags.m4]) m4_include([build/autotools/MaintainerFlags.m4]) m4_include([build/autotools/Optimizations.m4]) m4_include([build/autotools/Coverage.m4]) m4_include([build/autotools/LDVersionScript.m4]) m4_include([build/autotools/WeakSymbols.m4]) # We would put AM_INIT_AUTOMAKE into SetupAutomake.m4, but seems to cause # autoconf errors. AM_INIT_AUTOMAKE([foreign subdir-objects tar-ustar]) AM_MAINTAINER_MODE([enable]) m4_include([build/autotools/SetupAutomake.m4]) AC_CONFIG_FILES([ Makefile build/version src/libmongoc-1.0.pc src/libmongoc-ssl-1.0.pc src/libmongoc-priv.pc src/mongoc/mongoc-config.h src/mongoc/mongoc-version.h doc/installing.page doc/mongoc_version.page ]) m4_include([build/autotools/Libbson.m4]) m4_include([build/autotools/PrintBuildConfiguration.m4]) libmongoc-1.3.1/doc/000077500000000000000000000000001264720626300142425ustar00rootroot00000000000000libmongoc-1.3.1/doc/.gitignore000066400000000000000000000001341264720626300162300ustar00rootroot00000000000000*.7 html/*.html html/*.css html/*.js html/*.png man/*.3 installing.page mongoc_version.page libmongoc-1.3.1/doc/Makefile.am000066400000000000000000000001131264720626300162710ustar00rootroot00000000000000EXTRA_DIST += $(wildcard doc/*.page) build/libbson.xsl dist-hook: man html libmongoc-1.3.1/doc/advanced-connections.page000066400000000000000000000102371264720626300211700ustar00rootroot00000000000000 Advanced Connections

The following guide contains information specific to certain types of MongoDB configurations.

For an example of connecting to a simple standalone server, see the Tutorial. To establish a connection with authentication options enabled, see the Authentication page.

Connecting to a Replica Set

Connecting to a replica set is much like connecting to a standalone MongoDB server. Simply specify the replica set name using the ?replicaSet=myreplset URI option.

#include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_init (); /* Create our MongoDB Client */ client = mongoc_client_new ("mongodb://host01:27017,host02:27017,host03:27017/?replicaSet=myreplset"); /* Do some work */ /* TODO */ /* Clean up */ mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Multiple hostnames can be specified in the MongoDB connection string URI, with a comma separating hosts in the seed list.

It is recommended to use a seed list of members of the replica set to allow the driver to connect to any node.

Connecting to a Sharded Cluster

To connect to a sharded cluster, specify the mongos nodes the client should connect to. The C Driver will automatically detect that it has connected to a mongos sharding server.

If more than one hostname is specified, a seed list will be created to attempt failover between the mongos instances.

Specifying the replicaSet parameter when connecting to a mongos sharding server is invalid.

#include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_init (); /* Create our MongoDB Client */ client = mongoc_client_new ("mongodb://myshard01:27017/"); /* Do something with client ... */ /* Free the client */ mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>
Connecting to an IPv6 Address

The MongoDB C Driver will automatically resolve IPv6 addresses from host names. However, to specify an IPv6 address directly, wrap the address in [].

Connecting to a UNIX Domain Socket

On UNIX-like systems, the C Driver can connect directly to a MongoDB server using a UNIX domain socket. Simply pass the path to the socket, which must be suffixed with .sock.

Connecting directly to a UNIX domain socket is not a common practice.

Additional Connection Options

A variety of connection options for the MongoDB URI can be found here.

libmongoc-1.3.1/doc/aggregate.page000066400000000000000000000143101264720626300170250ustar00rootroot00000000000000 Aggregation Framework Examples

This document provides a number of practical examples that display the capabilities of the aggregation framework.

The Aggregations using the Zip Codes Data Set examples uses a publicly available data set of all zipcodes and populations in the United States. These data are available at: zips.json.

Requirements

MongoDB, version 2.2.0 or later. MongoDB C driver, version 0.96.0 or later.

Let's check if everything is installed.

Use the following command to load zips.json data set into mongod instance:

$ mongoimport --drop -d test -c zipcodes zips.json

Let's use the MongoDB shell to verify that everything was imported successfully.

$ mongo test MongoDB shell version: 2.6.1 connecting to: test > db.zipcodes.count() 29467 > db.zipcodes.findOne()
Aggregations using the Zip Codes Data Set

Each document in this collection has the following form:

In these documents:

The _id field holds the zipcode as a string.

The city field holds the city name.

The state field holds the two letter state abbreviation.

The pop field holds the population.

The loc field holds the location as a [latitude, longitude] array.

States with Populations Over 10 Million

To get all states with a population greater than 10 million, use the following aggregation pipeline:

You should see a result like the following:

The above aggregation pipeline is build from two pipeline operators: $group and $match.

The $group pipeline operator requires _id field where we specify grouping; remaining fields specify how to generate composite value and must use one of the group aggregation functions: $addToSet, $first, $last, $max, $min, $avg, $push, $sum. The $match pipeline operator syntax is the same as the read operation query syntax.

The $group process reads all documents and for each state it creates a separate document, for example:

{ "_id" : "WA", "total_pop" : 4866692 }

The total_pop field uses the $sum aggregation function to sum the values of all pop fields in the source documents.

Documents created by $group are piped to the $match pipeline operator. It returns the documents with the value of total_pop field greater than or equal to 10 million.

Average City Population by State

To get the first three states with the greatest average population per city, use the following aggregation:

This aggregate pipeline produces:

The above aggregation pipeline is build from three pipeline operators: $group, $sort and $limit.

The first $group operator creates the following documents:

Note, that the $group operator can't use nested documents except the _id field.

The second $group uses these documents to create the following documents:

These documents are sorted by the avg_city_pop field in descending order. Finally, the $limit pipeline operator returns the first 3 documents from the sorted set.

libmongoc-1.3.1/doc/authentication.page000066400000000000000000000147671264720626300201360ustar00rootroot00000000000000 Authentication

This guide covers the use of authentication options with the MongoDB C Driver. Ensure that the MongoDB server is also properly configured for authentication before making a connection. For more information, see the MongoDB security documentation.

Basic Authentication

The MongoDB C driver supports challenge response authentication (sometimes known as MONGODB-CR) through the use of MongoDB connection URIs.

Simply provide the username and password as one would with an HTTP URL, as well as the database to authenticate against via authSource.

mongoc_client_t *client = mongoc_client_new ("mongodb://user:password@localhost/?authSource=mydb");
GSSAPI (Kerberos) Authentication

Kerberos support is only provided in environments supported by the cyrus-sasl Kerberos implementation. This currently limits support to UNIX-like environments.

GSSAPI (Kerberos) authentication is available in the Enterprise Edition of MongoDB, version 2.4 and newer. To authenticate using GSSAPI, the MongoDB C driver must be installed with SASL support. Run the kinit command before using the following authentication methods:

$ kinit mongodbuser@EXAMPLE.COM mongodbuser@EXAMPLE.COM's Password: $ klist Credentials cache: FILE:/tmp/krb5cc_1000 Principal: mongodbuser@EXAMPLE.COM Issued Expires Principal Feb 9 13:48:51 2013 Feb 9 23:48:51 2013 krbtgt/EXAMPLE.COM@EXAMPLE.COM

Now authenticate using the MongoDB URI. GSSAPI authenticates against the $external virtual database, so a database does not need to be specified in the URI. Note that the Kerberos principal must be URL-encoded:

The default service name used by MongoDB and the MongoDB C driver is mongodb. A custom service name can be specified with the gssapiServiceName option:

When encountering errors such as Invalid net address, check if the application is behind a NAT (Network Address Translation) firewall. If so, create a ticket that uses forwardable and addressless Kerberos tickets. This can be done by passing -f -A to kinit.

$ kinit -f -A mongodbuser@EXAMPLE.COM
SSL Authentication

The MongoDB C Driver must be compiled with the --enable-ssl option to use SSL authentication.

To connect to a MongoDB server enabled with SSL, add the ?ssl=true option in the MongoDB URI.

Connecting to a server that does not support SSL will fail if the ?ssl=true parameter is provided in the URI. This is to prevent unintentional information leak.

SASL Plain Authentication

The MongoDB C Driver must be compiled with SASL support in order to use SASL PLAIN authentication.

MongoDB Enterprise Edition versions 2.5.0 and newer support the SASL PLAIN authentication mechanism, initially intended for delegating authentication to an LDAP server. Using the SASL PLAIN mechanism is very similar to the challenge response mechanism with usernames and passwords. These examples use the $external virtual database for LDAP support:

SASL PLAIN is a clear-text authentication mechanism. It is strongly recommended to connect to MongoDB using SSL with certificate validation when using the PLAIN mechanism.

X.509 Certificate Authentication

The MongoDB C Driver must be compiled with SSL support for X.509 authentication support.

The MONGODB-X509 mechanism authenticates a username derived from the distinguished subject name of the X.509 certificate presented by the driver during SSL negotiation. This authentication method requires the use of SSL connections with certificate validation and is available in MongoDB 2.5.1 and newer:

MONGODB-X509 authenticates against the $external database, so specifying a database is not required.

libmongoc-1.3.1/doc/basic-troubleshooting.page000066400000000000000000000147561264720626300214230ustar00rootroot00000000000000 Basic Troubleshooting
Troubleshooting Checklist

The following is a short list of things to check when you have a problem.

Did you call mongoc_init() in main()? If not, you will likely see a segfault.

Have you leaked any clients or cursors as can be found with mongoc-stat PID?

Have packets been delivered to the server? See egress bytes from mongoc-stat PID.

Does valgrind show any leaks? Ensure you call mongoc_cleanup() at the end of your process to cleanup lingering allocations from the MongoDB C driver.

If compiling your own copy of MongoDB C driver, consider configuring with --enable-tracing to enable function tracing and hex dumps of network packets to STDERR and STDOUT.

Performance Counters

The MongoDB C driver comes with a unique feature to help developers and sysadmins troubleshoot problems in production. Performance counters are available for each process using the driver. The counters can be accessed outside of the application process via a shared memory segment. This means that you can graph statistics about your application process easily from tools like Munin or Nagios. Your author often uses watch --interval=0.5 -d mongoc-stat $PID to monitor an application.

Counters are currently available on UNIX-like platforms that support shared memory segments.

Available Counters

Active and Disposed Cursors

Active and Disposed Clients, Client Pools, and Socket Streams.

Number of operations sent and received, by type.

Bytes transferred and received.

Authentication successes and failures.

Number of wire protocol errors.

To access counters for a given process, simply provide the process id to the mongoc-stat program installed with the MongoDB C Driver.

$ mongoc-stat 22203
Submitting a Bug Report

Think you’ve found a bug? Want to see a new feature in the MongoDB C driver? Please open a case in our issue management tool, JIRA:

Create an account and login.

Navigate to the CDRIVER project.

Click Create Issue - Please provide as much information as possible about the issue type and how to reproduce it.

Bug reports in JIRA for all driver projects (i.e. CDRIVER, CSHARP, JAVA) and the Core Server (i.e. SERVER) project are public.

libmongoc-1.3.1/doc/bulk.page000066400000000000000000000204741264720626300160440ustar00rootroot00000000000000 Bulk Write Operations

This tutorial explains how to take advantage of MongoDB C driver bulk write operation features. Executing write operations in batches reduces the number of network round trips, increasing write throughput.

Bulk Insert

New in MongoDB C driver 0.94.2.

First we need to fetch a bulk operation handle from the mongoc_collection_t. This can be performed in either ordered or unordered mode. Unordered mode allows for greater parallelization when working with sharded clusters.

We can now start inserting documents to the bulk operation. These will be buffered until we execute the operation.

The bulk operation will coalesce insertions as a single batch for each consecutive call to mongoc_bulk_operation_insert(). This creates a pipelined effect when possible.

The bulk operation API will automatically handle MongoDB servers < 2.6 by speaking the old wire protocol. However, some performance degredation may occur.

To execute the bulk operation and receive the result we call mongoc_bulk_operation_execute().

Example reply document:

{"nInserted" : 10000, "nMatched" : 0, "nModified" : 0, "nRemoved" : 0, "nUpserted" : 0, "writeErrors" : [] "writeConcernErrors" : [] }
Mixed Bulk Write Operations

New in MongoDB C driver 0.94.2

MongoDB C driver also supports executing mixed bulk write operations. A batch of insert, update, and remove operations can be executed together using the bulk write operations API.

Though the following API will work with all versions of MongoDB, it is designed to be used with MongoDB versions >= 2.6. Much better bulk insert performance can be achieved with older versions of MongoDB through the deprecated mongoc_collection_insert_bulk() method.

Ordered Bulk Write Operations

Ordered bulk write operations are batched and sent to the server in the order provided for serial execution. The reply document describes the type and count of operations performed.

Example reply document:

The index field in the upserted array is the 0-based index of the upsert operation; in this example, the sixth operation of the overall bulk operation was an upsert, so its index is 5.

nModified is only reported when using MongoDB 2.6 and later, otherwise the field is omitted.

Unordered Bulk Write Operations

Unordered bulk write operations are batched and sent to the server in arbitrary order where they may be executed in parallel. Any errors that occur are reported after all operations are attempted.

In the next example the first and third operations fail due to the unique constraint on _id. Since we are doing unordered execution the second and fourth operations succeed.

Example reply document:

The bson_error_t domain is MONGOC_ERROR_COMMAND and its code is 11000.

Bulk Operation Bypassing Document Validation

This feature is only available when using MongoDB 3.2 and later.

By default bulk operations are validated against the schema, if any is defined. In certain cases however it may be necessary to bypass the document validation.

Running the above example will result in:

The bson_error_t domain is MONGOC_ERROR_COMMAND.

Bulk Operation Write Concerns

By default bulk operations are executed with the write_concern of the collection they are executed against. A custom write concern can be passed to the mongoc_collection_create_bulk_operation() method. Write concern errors (e.g. wtimeout) will be reported after all operations are attempted, regardless of execution order.

Example reply document and error message:

The bson_error_t domain is MONGOC_ERROR_WRITE_CONCERN if there are write concern errors and no write errors. Write errors indicate failed operations, so they take precedence over write concern errors, which mean merely that the write concern is not satisfied yet.

Further Reading

See the Driver Bulk API Spec, which describes bulk write operations for all MongoDB drivers.

libmongoc-1.3.1/doc/cursors.page000066400000000000000000000073261264720626300166100ustar00rootroot00000000000000 Cursors
Handling Cursor Failures

Cursors exist on a MongoDB server. However, the mongoc_cursor_t structure gives the local process a handle to the cursor. It is possible for errors to occur on the server while iterating a cursor on the client. Even a network partition may occur. This means that applications should be robust in handling cursor failures.

While iterating cursors, you should check to see if an error has occurred. See the following example for how to robustly check for errors.

Destroying Server-Side Cursors

The MongoDB C driver will automatically destroy a server-side cursor when mongoc_cursor_destroy() is called. Failure to call this function when done with a cursor will leak memory client side as well as consume extra memory server side. If the cursor was configured to never timeout, it will become a memory leak on the server.

Tailable Cursors

Tailable cursors are cursors that remain open even after they've returned a final result. This way, if more documents are added to a collection (i.e., to the cursor's result set), then you can continue to call mongoc_cursor_next() to retrieve those additional results.

Here's a complete test case that demonstrates the use of tailable cursors.

Note that tailable cursors are for capped collections only.

<file>mongoc-tail.c</file> An example to tail the oplog from a replicaSet.

Let's compile and run this example against a replica set to see updates as they are made.

$ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet { "ts" : { "$timestamp" : { "t" : 1400023818, "i" : 1 } }, "h" : -8458503739429355503, "v" : 2, "op" : "i", "ns" : "test.test", "o" : { "_id" : { "$oid" : "5372ab0a25164be923d10d50" } } }

The line of output is a sample from performing db.test.insert({}) from the mongo shell on the given replicaSet.

See also mongoc_cursor_set_max_await_time_ms.

libmongoc-1.3.1/doc/deleting-document.page000066400000000000000000000045451264720626300205170ustar00rootroot00000000000000 Deleting a Document

This example illustrates the use of mongoc_collection_remove() to delete documents.

The following code inserts a sample document into the database "mydb" and collection "mycoll". Then, it deletes all documents matching {"hello" : "world"}.

<file>delete.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; bson_oid_t oid; bson_t *doc; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "test", "test"); doc = bson_new (); bson_oid_init (&oid, NULL); BSON_APPEND_OID (doc, "_id", &oid); BSON_APPEND_UTF8 (doc, "hello", "world"); if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) { printf ("Insert failed: %s\n", error.message); } bson_destroy (doc); doc = bson_new (); BSON_APPEND_OID (doc, "_id", &oid); if (!mongoc_collection_remove (collection, MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) { printf ("Delete failed: %s\n", error.message); } bson_destroy (doc); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o delete delete.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./delete

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 delete.c C:\> delete

Use the MongoDB shell to prove that the documents have been removed successfully.

$ mongo MongoDB shell version: 3.0.6 connecting to: test > use mydb switched to db mydb > db.mycoll.count({"hello" : "world"}) 0 >
libmongoc-1.3.1/doc/executing-command.page000066400000000000000000000051771264720626300205210ustar00rootroot00000000000000 Executing Commands

The driver provides helper functions for executing MongoDB commands on client, database and collection structures. These functions return cursors; the _simple variants return booleans indicating success or failure.

This example executes the collStats command against the collection "mycoll" in database "mydb".

<file>executing.c</file> #include #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; bson_error_t error; bson_t *command; bson_t reply; char *str; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); command = BCON_NEW ("collStats", BCON_UTF8 ("mycoll")); if (mongoc_collection_command_simple (collection, command, NULL, &reply, &error)) { str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); } else { fprintf (stderr, "Failed to run command: %s\n", error.message); } bson_destroy (command); bson_destroy (&reply); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o executing executing.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./executing { "ns" : "mydb.mycoll", "count" : 1, "size" : 48, "avgObjSize" : 48, "numExtents" : 1, "storageSize" : 8192, "lastExtentSize" : 8192.000000, "paddingFactor" : 1.000000, "userFlags" : 1, "capped" : false, "nindexes" : 1, "indexDetails" : { }, "totalIndexSize" : 8176, "indexSizes" : { "_id_" : 8176 }, "ok" : 1.000000 }

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 executing.c C:\> executing { "ns" : "mydb.mycoll", "count" : 1, "size" : 48, "avgObjSize" : 48, "numExtents" : 1, "storageSize" : 8192, "lastExtentSize" : 8192.000000, "paddingFactor" : 1.000000, "userFlags" : 1, "capped" : false, "nindexes" : 1, "indexDetails" : { }, "totalIndexSize" : 8176, "indexSizes" : { "_id_" : 8176 }, "ok" : 1.000000 }
libmongoc-1.3.1/doc/finding-document.page000066400000000000000000000103411264720626300203310ustar00rootroot00000000000000 Finding a Document

To query a MongoDB collection with the C driver, use the function mongoc_collection_find(). This returns a cursor to the matching documents. The following examples iterate through the result cursors and print the matches to stdout as JSON strings.

Note that mongoc_collection_find uses a document as a query specifier; for example,

{ "color" : "red" }

will match any document with a field named "color" with value "red". An empty document {} can be used to match all documents.

This first example uses an empty query specifier to find all documents in the database "mydb" and collection "mycoll".

<file>find.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; const bson_t *doc; bson_t *query; char *str; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); query = bson_new (); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL); while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_json (doc, NULL); printf ("%s\n", str); bson_free (str); } bson_destroy (query); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o find find.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./find { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 find.c C:\> find { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

To look for a specific document, add a specifier to query. This example adds a call to BSON_APPEND_UTF8() to look for all documents matching {"hello" : "world"}.

<file>find-specific.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; const bson_t *doc; bson_t *query; char *str; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); query = bson_new (); BSON_APPEND_UTF8 (query, "hello", "world"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL); while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_json (doc, NULL); printf ("%s\n", str); bson_free (str); } bson_destroy (query); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]> $ gcc -o find-specific find-specific.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./find-specific { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" } C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 find-specific.c C:\> find-specific { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }
libmongoc-1.3.1/doc/html/000077500000000000000000000000001264720626300152065ustar00rootroot00000000000000libmongoc-1.3.1/doc/html/Makefile.am000066400000000000000000000014111264720626300172370ustar00rootroot00000000000000BUILT_HTML_FILES = $(patsubst doc/%.page,doc/html/%.html,$(wildcard doc/*.page)) CLEANFILES += $(wildcard doc/html/*.html) CLEANFILES += $(wildcard doc/html/*.css) CLEANFILES += $(wildcard doc/html/*.js) CLEANFILES += $(wildcard doc/html/*.png) %.html: ../%.page $(AM_V_GEN)$(YELP_BUILD) html -o doc/html/ doc html: $(BUILT_HTML_FILES) YELP_HTML_FILES = \ doc/html/C.css \ doc/html/jquery.js \ doc/html/jquery.syntax.brush.clang.js \ doc/html/jquery.syntax.core.js \ doc/html/jquery.syntax.js \ doc/html/jquery.syntax.layout.yelp.js \ doc/html/yelp-note-tip.png \ doc/html/yelp-note-warning.png \ doc/html/yelp-note.png \ doc/html/yelp.js EXTRA_DIST += $(wildcard doc/html/*.html) EXTRA_DIST += $(wildcard doc/html/*.css) EXTRA_DIST += $(wildcard doc/html/*.js) libmongoc-1.3.1/doc/index.page000066400000000000000000000022611264720626300162100ustar00rootroot00000000000000 MongoDB C Driver A Cross Platform MongoDB Client Library for C
Installation
Tutorial
Basic Operations
Advanced Connections
Authentication
Cursors
Bulk Operations
Aggregation Framework
Client Side Document Matching
Troubleshooting
API Reference
libmongoc-1.3.1/doc/inserting-document.page000066400000000000000000000044211264720626300207170ustar00rootroot00000000000000 Inserting a Document

To insert documents into a collection, first obtain a handle to a mongoc_collection_t via a mongoc_client_t. Then, use mongoc_collection_insert() to add BSON documents to the collection. This example inserts into the database "mydb" and collection "mycoll".

When finished, ensure that allocated structures are freed by using their respective destroy functions.

<file>insert.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; bson_oid_t oid; bson_t *doc; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); doc = bson_new (); bson_oid_init (&oid, NULL); BSON_APPEND_OID (doc, "_id", &oid); BSON_APPEND_UTF8 (doc, "hello", "world"); if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) { fprintf (stderr, "%s\n", error.message); } bson_destroy (doc); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o insert insert.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./insert

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 insert.c C:\> insert

To verify that the insert succeeded, connect with the MongoDB shell.

$ mongo MongoDB shell version: 3.0.6 connecting to: test > use mydb switched to db mydb > db.mycoll.find() { "_id" : ObjectId("55ef43766cb5f36a3bae6ee4"), "hello" : "world" } >
libmongoc-1.3.1/doc/installing.page.in000066400000000000000000000235311264720626300176550ustar00rootroot00000000000000 Installing the MongoDB C Driver

The following guide will step you through the process of downloading, building, and installing the current release of the MongoDB C Driver.

Supported Platforms

The MongoDB C Driver is continuously tested on GNU/Linux, Windows 7, Mac OS X 10.10, and Solaris 11 (Intel and Sparc). GCC, Clang, and Visual Studio 2013 compilers are continuously tested.

The driver supports the following operating systems and CPU architectures:

Operating Systems CPU Architectures Compiler Toolchain

GNU/Linux

Solaris 11

Mac OS X 10.6 and newer

Windows Vista, 7, and 8

FreeBSD

x86 and x86_64

ARM

PPC

SPARC

GCC 4.1 and newer

Clang 3.3 and newer

Microsoft Visual Studio 2013 and newer

Oracle Solaris Studio 12

MinGW

Building on Unix
Prerequisites

OpenSSL is required for authentication or for SSL connections to MongoDB. Kerberos or LDAP support requires Cyrus SASL.

To install all optional dependencies on RedHat / Fedora:

$ sudo yum install pkg-config openssl-devel cyrus-sasl-devel

On Debian / Ubuntu:

$ sudo apt-get install pkg-config libssl-dev libsasl2-dev

On FreeBSD:

$ su -c 'pkg install pkgconf openssl cyrus-sasl2'
Building from a release tarball

Unless you intend on contributing to the mongo-c-driver, you will want to build from a release tarball.

The most recent release of libmongoc is @MONGOC_RELEASED_VERSION@ and can be downloaded here. The following snippet will download and extract the driver, and configure it:

$ wget https://github.com/mongodb/mongo-c-driver/releases/download/@MONGOC_RELEASED_VERSION@/mongo-c-driver-@MONGOC_RELEASED_VERSION@.tar.gz $ tar xzf mongo-c-driver-@MONGOC_RELEASED_VERSION@.tar.gz $ cd mongo-c-driver-@MONGOC_RELEASED_VERSION@ $ ./configure

If configure completed successfully, you'll see something like the following describing your build configuration.

libmongoc was configured with the following options: Build configuration: Enable debugging (slow) : no Compile with debug symbols (slow) : no Enable GCC build optimization : yes Enable automatic binary hardening : yes Code coverage support : no Cross Compiling : no Fast counters : no SASL : sasl2 SSL : yes Libbson : bundled Documentation: Generate man pages : no Install man pages : no

mongo-c-driver contains a copy of libbson, in case your system does not already have libbson installed. The configure script will detect if libbson is not installed and use the bundled libbson.

$ make $ sudo make install
Building from git

To build an unreleased version of the driver from git requires additional dependencies.

RedHat / Fedora:

$ sudo yum install git gcc automake autoconf libtool

Debian / Ubuntu:

$ sudo apt-get install git gcc automake autoconf libtool

FreeBSD:

$ su -c 'pkg install git gcc automake autoconf libtool'

Once you have the dependencies installed, clone the repository and build the current master or a particular release tag:

$ git clone https://github.com/mongodb/mongo-c-driver.git $ cd mongo-c-driver $ git checkout x.y.z # To build a particular release $ ./autogen.sh --with-libbson=bundled $ make $ sudo make install
Generating the documentation

Install the yelp-tools and yelp-xsl packages, then:

$ ./configure --enable-html-docs --enable-man-pages $ make man html
Building on Mac OS X
Prerequisites
XCode Command Line Tools

To install the XCode Command Line Tools, just type xcode-select --install in the Terminal and follow the instructions.

OpenSSL support on El Capitan

Beginning in OS X 10.11 El Capitan, OS X no longer includes the OpenSSL headers. To build the driver with SSL on El Capitan and later, first install Homebrew according to its instructions, then:

$ brew install openssl $ export LDFLAGS="-L/usr/local/opt/openssl/lib" $ export CPPFLAGS="-I/usr/local/opt/openssl/include"
Building on OS X

Download the latest release tarball:

$ curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/@MONGOC_RELEASED_VERSION@/mongo-c-driver-@MONGOC_RELEASED_VERSION@.tar.gz $ tar xzf mongo-c-driver-@MONGOC_RELEASED_VERSION@.tar.gz $ cd mongo-c-driver-@MONGOC_RELEASED_VERSION@

Build and install the driver:

$ ./configure $ make $ sudo make install
Generating the documentation on OS X

Homebrew is required to generate the driver's HTML documentation and man pages:

$ brew install yelp-xsl yelp-tools $ ./configure --enable-html-docs --enable-man-pages $ make man html
Installing on Mac OS X

To build the C Driver on a Mac, install the prerequisites in order to build it from source. It is recommended to use Homebrew:

$ brew install git automake autoconf libtool pkgconfig

Additionally, XCode is required. The driver can then be installed by following the directions for building from source.

Building on Windows

Building on Windows requires Windows Vista or newer and Visual Studio 2010 or newer. Additionally, cmake is required to generate Visual Studio project files.

Let's start by generating Visual Studio project files for libbson, a dependency of the C driver. The following assumes we are compiling for 64-bit Windows using Visual Studio 2010 Express which can be freely downloaded from Microsoft.

cd mongo-c-driver-@MONGOC_RELEASED_VERSION@\src\libbson cmake -G "Visual Studio 10 Win64" "-DCMAKE_INSTALL_PREFIX=C:\mongo-c-driver"

(Run cmake -LH . for a list of other options.)

Now that we have project files generated, we can either open the project in Visual Studio or compile from the command line. Let's build using the command line program msbuild.exe

msbuild.exe ALL_BUILD.vcxproj

Now that libbson is compiled, let's install it using msbuild. It will be installed to the path specified by CMAKE_INSTALL_PREFIX.

msbuild.exe INSTALL.vcxproj

You should now see libbson installed in C:\mongo-c-driver

.

Now let's do the same for the MongoDB C driver.

cd mongo-c-driver-@MONGOC_RELEASED_VERSION@ cmake -G "Visual Studio 2010 Win64" "-DCMAKE_INSTALL_PREFIX=C:\mongo-c-driver" "-DBSON_ROOT_DIR=C:\mongo-c-driver" msbuild.exe ALL_BUILD.vcxproj msbuild.exe INSTALL.vcxproj

All of the MongoDB C Driver's components will now be found in C:\mongo-c-driver.

libmongoc-1.3.1/doc/logging.page000066400000000000000000000102201264720626300165210ustar00rootroot00000000000000 Logging MongoDB C driver Logging Abstraction
Synopsis

The MongoDB C driver comes with an abstraction for logging that you can use in your application, or integrate with an existing logging system.

Macros

To make logging a little less painful, various helper macros are provided. See the following example.

Tracing

If compiling your own copy of the MongoDB C driver, consider configuring with --enable-tracing to enable function tracing and hex dumps of network packets to STDERR and STDOUT during development and debugging.

This is especially useful when debugging what may be going on internally in the driver.

Trace messages can be enabled and disabled by calling mongoc_log_trace_enable() and mongoc_log_trace_disable()

Compiling the driver with --enable-tracing will affect its performance. Disabling tracing with mongoc_log_trace_disable() significantly reduces the overhead, but cannot remove it completely.

Custom Log Handlers

The default log handler prints a timestamp and the log message to stdout, or to stderr for warnings, critical messages, and errors. You can override the handler with mongoc_log_set_handler(). Your handler function is called in a mutex for thread safety.

To restore the default handler:

Disable logging

To disable all logging, including warnings, critical messages and errors, you need to provide an empty log handler

libmongoc-1.3.1/doc/mallard2man.py000077500000000000000000000277331264720626300170250ustar00rootroot00000000000000#!/usr/bin/env python # # mallard2man.py # # Copyright (C) 2014 MongoDB, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # 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 . # COPYRIGHT_HOLDER = "MongoDB, Inc." GROUP = "MongoDB C Driver" BUG_URL = 'https://jira.mongodb.org/browse/CDRIVER' """ This script is mean to convert a fairly basic mallard format documentation page to a groff styled man page. """ import os import re import sys import codecs from datetime import datetime from xml.etree import ElementTree INCLUDE = '{http://www.w3.org/2001/XInclude}include' TITLE = '{http://projectmallard.org/1.0/}title' SUBTITLE = '{http://projectmallard.org/1.0/}subtitle' SECTION = '{http://projectmallard.org/1.0/}section' INFO = '{http://projectmallard.org/1.0/}info' ITEM = '{http://projectmallard.org/1.0/}item' LISTING = '{http://projectmallard.org/1.0/}listing' LIST = '{http://projectmallard.org/1.0/}list' LINK = '{http://projectmallard.org/1.0/}link' LINKS = '{http://projectmallard.org/1.0/}links' SYNOPSIS = '{http://projectmallard.org/1.0/}synopsis' CODE = '{http://projectmallard.org/1.0/}code' P = '{http://projectmallard.org/1.0/}p' SCREEN = '{http://projectmallard.org/1.0/}screen' EM = '{http://projectmallard.org/1.0/}em' NOTE = '{http://projectmallard.org/1.0/}note' TABLE = '{http://projectmallard.org/1.0/}table' TR = '{http://projectmallard.org/1.0/}tr' TD = '{http://projectmallard.org/1.0/}td' OUTPUT = '{http://projectmallard.org/1.0/}output' # Matches "\" and "-", but not "\-". replaceables = re.compile(r'(\\(?!-))|((? section element. self.sections_map = {} def _parse(self): self.tree = ElementTree.ElementTree() self.tree.parse(open(self.inFile)) self.root = self.tree.getroot() # Python's standard ElementTree doesn't store an element's parent on # the element. Make a child->parent map. try: iterator = self.tree.iter() except AttributeError: # Python 2.6. iterator = self.tree.getiterator() self.parent_map = dict((c, p) for p in iterator for c in p) def _get_parent(self, ele): return self.parent_map[ele] def _extract(self): # Extract the title and subtitle. for child in self.root.getchildren(): if child.tag == TITLE: # A title like "Version Checks" can't have spaces, otherwise # the "whatis" entry can't be parsed from the man page title. self.title = child.text.strip().replace(' ', '_') elif child.tag == SUBTITLE: self.subtitle = child.text.strip() elif child.tag == SECTION: if child.get('id'): self.sections_map[child.get('id')] = child self.sections.append(child) if not self.subtitle and 'description' in self.sections_map: # No "subtitle" element, use description section title as subtitle. self.subtitle = self._section_text(self.sections_map['description']) def _section_text(self, section): # Find

some text

. for child in section: if child.tag != TITLE: return self._textify_elem(child) def _textify_elem(self, elem): return ''.join(elem.itertext()).strip() def _writeComment(self, text=''): lines = text.split('\n') for line in lines: self.outFile.write('.\\" ') self.outFile.write(line) self.outFile.write('\n') def _escape_char(self, match): c = match.group(0) if c == "-": return r"\(hy" elif c == "\\": return "\\e" assert False, "invalid char passed to _escape_char: %r" % c def _escape(self, text): # Avoid "hyphen-used-as-minus-sign" lintian warning about man pages, # and escape text like "\0" as "\\0". We'll replace all "-" with "\(hy", # which is an explicit hyphen, but leave alone the first line's # "name \- description" text. return replaceables.sub(self._escape_char, text) def _write(self, text): self._write_noescape(self._escape(text)) def _write_noescape(self, text): self.outFile.write(text) def _writeCommand(self, text): self._write(text) self._write('\n') def _writeLine(self, text): if text is not None: text = text.strip() if text.startswith('.'): text = '\\&' + text self._write(text) self._write('\n') def _generateHeader(self): year = datetime.utcnow().year self._writeComment('This manpage is Copyright (C) %s %s' % (year, COPYRIGHT_HOLDER)) self._writeComment('') self._writeComment( "Permission is granted to copy, distribute and/or modify this document\n" "under the terms of the GNU Free Documentation License, Version 1.3\n" "or any later version published by the Free Software Foundation;\n" "with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.\n" "A copy of the license is included in the section entitled \"GNU\n" "Free Documentation License\".") self._writeComment('') date = datetime.fromtimestamp(int(os.stat(self.inFile).st_mtime)).strftime('%Y-%m-%d') title = self.title.replace('()','').upper() self._write('.TH "%s" "%s" "%s" "%s"\n' % (title, self.section, date, GROUP)) self._write('.SH NAME\n') self._write_noescape('%s \\- %s\n' % (self.title, self.subtitle)) def _generateSection(self, section): # Try to render the title first for child in section.getchildren(): if child.tag == TITLE: s = child.text.strip().upper() self._writeCommand('.SH "%s"' % s) for child in section.getchildren(): self._generateElement(child) if child.tail: self._writeLine(child.tail) def _generateSynopsis(self, synopsis): self._writeCommand('.nf') for child in synopsis.getchildren(): self._generateElement(child) if child.tail: self._writeLine(child.tail) self._writeCommand('.fi') def _generateCode(self, code): text = code.text is_synopsis = self._get_parent(code).tag.endswith('synopsis') if text and '\n' not in text and not is_synopsis: text = text.replace('()', '(%s)' % self.section) self._writeCommand('.B ' + text) else: self._writeCommand('.nf') self._writeLine(code.text) for child in code.getchildren(): self._generateElement(child) self._writeCommand('.fi') def _generateNote(self, note): self._writeCommand('.B NOTE') self._writeCommand('.RS') for child in note.getchildren(): self._generateElement(child) if child.tail: self._writeLine(child.tail) self._writeCommand('.RE') def _generateP(self, p): if p.text: self._writeLine(p.text) for child in p.getchildren(): self._generateElement(child) if child.tail: self._writeLine(child.tail) def _generateScreen(self, screen): for child in screen.getchildren(): self._generateElement(child) def _generateListing(self, listing): for child in listing.getchildren(): self._generateElement(child) def _generateList(self, l): for child in l.getchildren(): self._generateElement(child) def _generateEM(self, em): self._writeCommand('.B %s' % em.text) def _generateOutput(self, output): self._generateCode(output) def _generateItem(self, item): self._writeCommand('.IP \\[bu] 2') for child in item.getchildren(): self._generateElement(child) def _generateElement(self, ele): if ele.tag == SECTION: self._generateSection(ele) elif ele.tag == SYNOPSIS: self._generateSynopsis(ele) elif ele.tag == CODE: self._generateCode(ele) elif ele.tag == OUTPUT: self._generateOutput(ele) elif ele.tag == P: self._generateP(ele) elif ele.tag == EM: self._generateEM(ele) elif ele.tag == LISTING: self._generateListing(ele) elif ele.tag == ITEM: self._generateItem(ele) elif ele.tag == LIST: self._generateList(ele) elif ele.tag == TITLE: pass elif ele.tag == SCREEN: self._generateScreen(ele) elif ele.tag == LINK: self._generateLink(ele) elif ele.tag == NOTE: self._generateNote(ele) elif ele.tag == TABLE: self._generateTable(ele) elif ele.tag == TR: self._generateTr(ele) elif ele.tag == TD: self._generateTd(ele) elif ele.tag == INCLUDE: f = ele.attrib['href'] f = os.path.join(self.relpath, f) d = codecs.open(f, 'r', encoding='utf-8').read() self._writeLine(d) else: print('unknown element type %s' % ele) def _generateTable(self, table): for child in table.getchildren(): self._generateElement(child) def _generateTr(self, tr): self._writeCommand('.TP') self._writeCommand('.B') for child in tr.getchildren(): self._generateElement(child) self._writeCommand('.LP') def _generateTd(self, td): for child in td.getchildren(): self._generateElement(child) def _generateLink(self, link): text = link.text if text and '()' in text: text = text.replace('()', '(%s)' % self.section) if text: self._writeCommand('.B ' + text) def _generateSections(self): for section in self.sections: self._generateElement(section) def _generateFooter(self): self._write('\n.B') self._write('\n.SH COLOPHON') self._write('\nThis page is part of %s.' % GROUP) self._write('\nPlease report any bugs at %s.' % BUG_URL.replace('-','\\-')) def _generate(self): self.realname = self.outFile self.outFile = codecs.open(self.outFile + '.tmp', 'w', encoding='utf-8') self._generateHeader() self._generateSections() self._generateFooter() os.rename(self.outFile.name, self.realname) self.outFile.close() def convert(self): self._parse() self._extract() self._generate() def main(filenames, section='3'): for inFile in filenames: dirName = os.path.dirname(inFile) + '/man/' baseName = os.path.basename(inFile) baseFile = os.path.splitext(baseName)[0] outFile = dirName + baseFile + '.' + section c = Convert(inFile, outFile, section) c.convert() if __name__ == '__main__': if len(sys.argv) < 3: print('usage: %s SECTION FILENAMES...' % sys.argv[0]) sys.exit(1) section = sys.argv[1] main(sys.argv[2:], section) sys.exit(0) libmongoc-1.3.1/doc/man/000077500000000000000000000000001264720626300150155ustar00rootroot00000000000000libmongoc-1.3.1/doc/man/Makefile.am000066400000000000000000000011131264720626300170450ustar00rootroot00000000000000BUILT_MAN_FILES = $(patsubst doc/%.page,doc/man/%.3,$(wildcard doc/*.page)) CLEANFILES += $(wildcard doc/man/*.3) dist_man_MANS = $(BUILT_MAN_FILES) # Automake (at least up to 1.10) mishandles dist_man_MANS inside conditionals. # Unlike with other dist primaries, the files are not distributed if the # conditional is false. # Work the bug around until it is fixed: dist_noinst_DATA = $(dist_man_MANS) man3_MANS = $(BUILT_MAN_FILES) %.3: ../%.page $(AM_V_GEN)./doc/mallard2man.py 3 $^ man: $(BUILT_MAN_FILES) EXTRA_DIST += $(wildcard doc/man/*.3) \ doc/mallard2man.py libmongoc-1.3.1/doc/matcher.page000066400000000000000000000042021264720626300165210ustar00rootroot00000000000000 Client Side Document Matching
Basic Document Matching (Deprecated)

This feature will be removed in version 2.0.

The MongoDB C driver supports matching a subset of the MongoDB query specification on the client.

Currently, basic numeric, string, subdocument, and array equality, $gt, $gte, $lt, $lte, $in, $nin, $ne, $exists, $type, $and, and $or are supported. As this is not the same implementation as the MongoDB server, some inconsistencies may occur. Please file a bug if you find such a case.

The following example performs a basic query against a BSON document.

example-matcher.c

The following example shows how to process a BSON stream from stdin and match it against a query. This can be useful if you need to perform simple matching against mongodump backups.

filter-bsondump.c

To test this, perform a mongodump of a single collection and pipe it to the program.

$ echo "db.test.insert({hello:'world'})" | mongo MongoDB shell version: 2.6.1 connecting to: test WriteResult({ "nInserted" : 1 }) bye $ mongodump -d test -c test -o - | filter-bsondump { "_id" : { "$oid" : "537afac9a70e5b4d556153bc" }, "hello" : "world" }
libmongoc-1.3.1/doc/mongoc_bulk_operation_delete.page000066400000000000000000000033221264720626300230010ustar00rootroot00000000000000 mongoc_bulk_operation_delete()
Synopsis

This function queues a delete operation as part of bulk that will delete all documents matching selector. To delete a single document, see mongoc_bulk_operation_remove_one().

Deprecated

This function is deprecated and should not be used in new code.

Please use mongoc_bulk_operation_remove() instead.

Parameters

bulk

A mongoc_bulk_operation_t.

selector

A bson_t.

Errors

Errors are propagated via mongoc_bulk_operation_execute().

libmongoc-1.3.1/doc/mongoc_bulk_operation_delete_one.page000066400000000000000000000033511264720626300236440ustar00rootroot00000000000000 mongoc_bulk_operation_delete_one()
Synopsis

This function queues a delete operation as part of bulk that will delete a single document matching selector. To delete a multiple documents, see mongoc_bulk_operation_delete().

Deprecated

This function is deprecated and should not be used in new code.

Please use mongoc_bulk_operation_remove_one() instead.

Parameters

bulk

A mongoc_bulk_operation_t.

selector

A bson_t.

Errors

Errors are propagated via mongoc_bulk_operation_execute().

libmongoc-1.3.1/doc/mongoc_bulk_operation_destroy.page000066400000000000000000000017071264720626300232350ustar00rootroot00000000000000 mongoc_bulk_operation_destroy()
Synopsis

Destroys a mongoc_bulk_operation_t and frees the structure.

Parameters

bulk

A mongoc_bulk_operation_t.

libmongoc-1.3.1/doc/mongoc_bulk_operation_execute.page000066400000000000000000000045521264720626300232070ustar00rootroot00000000000000 mongoc_bulk_operation_execute()
Synopsis

This function executes all operations queued into the bulk operation. If ordered was specified to mongoc_collection_create_bulk_operation(), then forward progress will be stopped upon the first error.

It is only valid to call mongoc_bulk_operation_execute() once. The mongoc_bulk_operation_t must be destroyed afterwards.

reply is always initialized, even upon failure. Callers must call bson_destroy() to release this potential allocation.

Parameters

bulk

A mongoc_bulk_operation_t.

reply

A bson_t.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

A non-zero hint of the peer node on success, otherwise 0 and error is set.

The reply document counts operations and collects error information. See Bulk Write Operations for examples.

libmongoc-1.3.1/doc/mongoc_bulk_operation_get_write_concern.page000066400000000000000000000023251264720626300252410ustar00rootroot00000000000000 mongoc_bulk_operation_get_write_concern()
Synopsis
Parameters

bulk

A mongoc_bulk_operation_t.

Description

Fetches the write concern to be used for bulk.

Returns

A mongoc_write_concern_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_bulk_operation_insert.page000066400000000000000000000025561264720626300230530ustar00rootroot00000000000000 mongoc_bulk_operation_insert()
Synopsis

Queue an insert of a single document into a bulk operation. The insert is not performed until mongoc_bulk_operation_execute() is called.

Parameters

bulk

A mongoc_bulk_operation_t.

document

A bson_t.

Errors

Errors are propagated via mongoc_bulk_operation_execute().

libmongoc-1.3.1/doc/mongoc_bulk_operation_remove.page000066400000000000000000000026601264720626300230400ustar00rootroot00000000000000 mongoc_bulk_operation_remove()
Synopsis

This function queues a delete operation as part of bulk that will delete all documents matching selector. To delete a single document, see mongoc_bulk_operation_remove_one().

Parameters

bulk

A mongoc_bulk_operation_t.

selector

A bson_t.

Errors

Errors are propagated via mongoc_bulk_operation_execute().

libmongoc-1.3.1/doc/mongoc_bulk_operation_remove_one.page000066400000000000000000000026771264720626300237110ustar00rootroot00000000000000 mongoc_bulk_operation_remove_one()
Synopsis

This function queues a delete operation as part of bulk that will delete a single document matching selector. To delete a multiple documents, see mongoc_bulk_operation_remove().

Parameters

bulk

A mongoc_bulk_operation_t.

selector

A bson_t.

Errors

Errors are propagated via mongoc_bulk_operation_execute().

libmongoc-1.3.1/doc/mongoc_bulk_operation_replace_one.page000066400000000000000000000036641264720626300240240ustar00rootroot00000000000000 mongoc_bulk_operation_replace_one()
Synopsis

Replace a single document as part of a bulk operation. This only queues the operation. To execute it, call mongoc_bulk_operation_execute().

Parameters

bulk

A mongoc_bulk_operation_t.

selector

A bson_t containing the selector to query.

document

A bson_t containing the replacement document.

upsert

true if this should be an upsert.

document may not contain fields with keys containing . or $.

Errors

Errors are propagated via mongoc_bulk_operation_execute().

libmongoc-1.3.1/doc/mongoc_bulk_operation_set_bypass_document_validation.page000066400000000000000000000023671264720626300300330ustar00rootroot00000000000000 mongoc_bulk_operation_set_bypass_document_validation()
Synopsis
Parameters

bulk

A mongoc_bulk_operation_t.

bypass

A boolean.

Description

Will bypass document validation for all operations part of this bulk.

libmongoc-1.3.1/doc/mongoc_bulk_operation_t.page000066400000000000000000000024461264720626300220100ustar00rootroot00000000000000 mongoc_bulk_operation_t Bulk Write Operations
Synopsis

The opaque type mongoc_bulk_operation_t provides an abstraction for submitting multiple write operations as a single batch.

After adding all of the write operations to the mongoc_bulk_operation_t, call mongoc_bulk_operation_execute() to execute the operation.

It is only valid to call mongoc_bulk_operation_execute() once. The mongoc_bulk_operation_t must be destroyed afterwards.

Functions
libmongoc-1.3.1/doc/mongoc_bulk_operation_update.page000066400000000000000000000042141264720626300230220ustar00rootroot00000000000000 mongoc_bulk_operation_update()
Synopsis

This function queues an update as part of a bulk operation. This does not execute the operation. To execute the entirety of the bulk operation call mongoc_bulk_operation_execute().

document MUST only contain fields whose key starts with $. See the update document specification for more details.

Parameters

bulk

A mongoc_bulk_operation_t.

selector

A bson_t containing the selector to query.

document

A bson_t containing the update document.

upsert

true if an upsert should be performed.

Errors

Errors are propagated via mongoc_bulk_operation_execute().

See Also

mongoc_bulk_operation_update_one()

libmongoc-1.3.1/doc/mongoc_bulk_operation_update_one.page000066400000000000000000000040651264720626300236670ustar00rootroot00000000000000 mongoc_bulk_operation_update_one()
Synopsis

This function queues an update as part of a bulk operation. It will only modify a single document on the MongoDB server. This function does not execute the operation. To execute the entirety of the bulk operation call mongoc_bulk_operation_execute().

document must only contain fields whose key starts with $. See the update document specification for more details.

Parameters

bulk

A mongoc_bulk_operation_t.

selector

A bson_t containing the selector to query.

document

A bson_t containing the update document.

upsert

true if an upsert should be performed.

See Also

mongoc_bulk_operation_update()

libmongoc-1.3.1/doc/mongoc_check_version.page000066400000000000000000000022641264720626300212700ustar00rootroot00000000000000 mongoc_check_version()
Synopsis
Parameters

required_major

The minimum major version required.

required_minor

The minimum minor version required.

required_micro

The minimum micro version required.

Returns

True if libmongoc's version is greater than or equal to the required version.

libmongoc-1.3.1/doc/mongoc_cleanup.page000066400000000000000000000014401264720626300200700ustar00rootroot00000000000000 mongoc_cleanup()
Synopsis
Description

This function is responsible for cleaning up after use of the MongoDB C driver. It will release any lingering allocated memory which can be useful when running under valgrind.

libmongoc-1.3.1/doc/mongoc_client_command.page000066400000000000000000000051331264720626300214200ustar00rootroot00000000000000 mongoc_client_command()
Synopsis

This function executes a command on the server using the database and command specification provided.

Parameters

client

A mongoc_client_t.

db_name

The name of the database to run the command on.

flags

A mongoc_query_flags_t.

skip

The number of result documents to skip.

limit

The maximum number of documents to return.

batch_size

The batch size of documents to return from the MongoDB server.

query

A bson_t containing the command specification.

fields

An optional bson_t containing the fields to return in result documents.

read_prefs

An optional mongoc_read_prefs_t.

Returns

This function will always return a mongoc_cursor_t if valid parameters are passed.

The cursor should be freed with mongoc_cursor_destroy().

libmongoc-1.3.1/doc/mongoc_client_command_simple.page000066400000000000000000000045501264720626300227730ustar00rootroot00000000000000 mongoc_client_command_simple()
Synopsis

This is a simplified interface to mongoc_client_command(). It returns the first document from the result cursor into reply.

reply is always set, and should be released with bson_destroy().

Parameters

client

A mongoc_client_t.

db_name

The name of the database to run the command on.

command

A bson_t containing the command specification.

read_prefs

A mongoc_read_prefs_t.

reply

A location for the resulting document.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

true if successful; otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_client_destroy.page000066400000000000000000000015741264720626300215000ustar00rootroot00000000000000 mongoc_client_destroy()
Synopsis

Release all resources associated with client and free the structure.

Parameters

client

A mongoc_client_t.

libmongoc-1.3.1/doc/mongoc_client_get_collection.page000066400000000000000000000033571264720626300230020ustar00rootroot00000000000000 mongoc_client_get_collection()
Synopsis

Get a newly allocated mongoc_collection_t for the collection named collection in the database named db.

Collections are automatically created on the MongoDB server upon insertion of the first document. There is no need to create a collection manually.

Parameters

client

A mongoc_client_t.

db

The name of the database containing the collection.

collection

The name of the collection.

Returns

A newly allocated mongoc_collection_t that should be freed with mongoc_collection_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_client_get_database.page000066400000000000000000000030161264720626300224030ustar00rootroot00000000000000 mongoc_client_get_database()
Synopsis

Get a newly allocated mongoc_database_t for the database named name.

Databases are automatically created on the MongoDB server upon insertion of the first document into a collection. There is no need to create a database manually.

Parameters

client

A mongoc_client_t.

name

The name of the database.

Returns

A newly allocated mongoc_database_t that should be freed with mongoc_database_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_client_get_database_names.page000066400000000000000000000037641264720626300236000ustar00rootroot00000000000000 mongoc_client_get_database_names()
Synopsis

This function queries the MongoDB server for a list of known databases.

Parameters

client

A mongoc_client_t.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

A NULL terminated vector of NULL-byte terminated strings. The result should be freed with bson_strfreev().

NULL is returned upon failure and error is set.

Examples
libmongoc-1.3.1/doc/mongoc_client_get_default_database.page000066400000000000000000000037031264720626300241120ustar00rootroot00000000000000 mongoc_client_get_default_database()
Synopsis

Get the database named in the MongoDB connection URI, or NULL if the URI specifies none.

Useful when you want to choose which database to use based only on the URI in a configuration file.

Parameters

client

A mongoc_client_t.

Returns

A newly allocated mongoc_database_t that should be freed with mongoc_database_destroy().

Example Default Database Example
libmongoc-1.3.1/doc/mongoc_client_get_gridfs.page000066400000000000000000000040161264720626300221160ustar00rootroot00000000000000 mongoc_client_get_gridfs()
Synopsis

The mongoc_client_get_gridfs() function shall create a new mongoc_gridfs_t. The db parameter is the name of the database which the gridfs instance should exist in. The prefix parameter corresponds to the gridfs collection namespacing; its default is "fs", thus the default GridFS collection names are "fs.files" and "fs.chunks".

Parameters

client

A mongoc_client_t.

db

The database name.

prefix

Optional prefix for gridfs collection names or NULL.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

A mongoc_gridfs_t on success, NULL upon failure and error is set.

libmongoc-1.3.1/doc/mongoc_client_get_max_bson_size.page000066400000000000000000000025631264720626300235050ustar00rootroot00000000000000 mongoc_client_get_max_bson_size()
Synopsis

The mongoc_client_get_max_bson_size() returns the maximum bson document size allowed by the cluster. Until a connection has been made, this will be the default of 16Mb.

Deprecated

This function is deprecated and should not be used in new code.

Parameters

client

A mongoc_client_t.

Returns

The server provided max bson size, or 16Mb if no connection has been established.

libmongoc-1.3.1/doc/mongoc_client_get_max_message_size.page000066400000000000000000000025771264720626300241750ustar00rootroot00000000000000 mongoc_client_get_max_message_size()
Synopsis

The mongoc_client_get_max_message_size() returns the maximum message size allowed by the cluster. Until a connection has been made, this will be the default of 40Mb.

Deprecated

This function is deprecated and should not be used in new code.

Parameters

client

A mongoc_client_t.

Returns

The server provided max message size, or 40Mb if no connection has been established.

libmongoc-1.3.1/doc/mongoc_client_get_read_concern.page000066400000000000000000000021411264720626300232570ustar00rootroot00000000000000 mongoc_client_get_read_concern()
Synopsis

Retrieve the default read concern configured for the client instance. The result should not be modified or freed.

Parameters

client

A mongoc_client_t.

Returns

A mongoc_read_concern_t.

libmongoc-1.3.1/doc/mongoc_client_get_read_prefs.page000066400000000000000000000021351264720626300227520ustar00rootroot00000000000000 mongoc_client_get_read_prefs()
Synopsis

Retrieves the default read preferences configured for the client instance. The result should not be modified or freed.

Parameters

client

A mongoc_client_t.

Returns

A mongoc_read_prefs_t.

libmongoc-1.3.1/doc/mongoc_client_get_server_status.page000066400000000000000000000037301264720626300235530ustar00rootroot00000000000000 mongoc_client_get_server_status()
Synopsis

Queries the server for the current server status. The result is stored in reply.

reply is always initialized, even in the case of failure. Always call bson_destroy() to release it.

Parameters

client

A mongoc_client_t.

read_prefs

A mongoc_read_prefs_t.

reply

A location for the result bson_t.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

true on success, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_client_get_uri.page000066400000000000000000000020661264720626300214420ustar00rootroot00000000000000 mongoc_client_get_uri()
Synopsis

Fetches the mongoc_uri_t used to create the client.

Parameters

client

A mongoc_client_t.

Returns

A mongoc_uri_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_client_get_write_concern.page000066400000000000000000000021501264720626300234760ustar00rootroot00000000000000 mongoc_client_get_write_concern()
Synopsis

Retrieve the default write concern configured for the client instance. The result should not be modified or freed.

Parameters

client

A mongoc_client_t.

Returns

A mongoc_write_concern_t.

libmongoc-1.3.1/doc/mongoc_client_new.page000066400000000000000000000023551264720626300205760ustar00rootroot00000000000000 mongoc_client_new()
Synopsis

Creates a new mongoc_client_t using the URI string provided.

Parameters

uri_string

A string containing the MongoDB connection URI.

Returns

A newly allocated mongoc_client_t if the URI parsed successfully, otherwise NULL.

See Also

mongoc_client_new_from_uri()

libmongoc-1.3.1/doc/mongoc_client_new_from_uri.page000066400000000000000000000023051264720626300224730ustar00rootroot00000000000000 mongoc_client_new_from_uri()
Synopsis

Creates a new mongoc_client_t using the mongoc_uri_t provided.

Parameters

uri

A mongoc_uri_t.

Returns

A newly allocated mongoc_client_t that should be freed with mongoc_client_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_client_pool_destroy.page000066400000000000000000000016421264720626300225250ustar00rootroot00000000000000 mongoc_client_pool_destroy()
Synopsis

Release all resources associated with pool, including freeing the structure.

Parameters

pool

A mongoc_client_pool_t.

libmongoc-1.3.1/doc/mongoc_client_pool_max_size.page000066400000000000000000000023241264720626300226510ustar00rootroot00000000000000 mongoc_client_pool_max_size()
Synopsis

This function sets the maximum number of pooled connections available from a mongoc_client_pool_t.

Parameters

pool

A mongoc_client_pool_t.

max_pool_size

The maximum number of connections which shall be available from the pool.

libmongoc-1.3.1/doc/mongoc_client_pool_min_size.page000066400000000000000000000023041264720626300226450ustar00rootroot00000000000000 mongoc_client_pool_min_size()
Synopsis

This function sets the minimum number of pooled connections kept in mongoc_client_pool_t.

Parameters

pool

A mongoc_client_pool_t.

min_pool_size

The minimum number of connections which shall be kept in the pool.

libmongoc-1.3.1/doc/mongoc_client_pool_new.page000066400000000000000000000023601264720626300216230ustar00rootroot00000000000000 mongoc_client_pool_new()
Synopsis

This function creates a new mongoc_client_pool_t using the mongoc_uri_t provided.

Parameters

uri

A mongoc_uri_t.

Returns

A newly allocated mongoc_client_pool_t that should be freed with mongoc_client_pool_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_client_pool_pop.page000066400000000000000000000021141264720626300216250ustar00rootroot00000000000000 mongoc_client_pool_pop()
Synopsis

Retrieve a mongoc_client_t from the client pool, possibly blocking until one is available.

Parameters

pool

A mongoc_client_pool_t.

Returns

A mongoc_client_t.

libmongoc-1.3.1/doc/mongoc_client_pool_push.page000066400000000000000000000021071264720626300220100ustar00rootroot00000000000000 mongoc_client_pool_push()
Synopsis

This function returns a mongoc_client_t back to the client pool.

Parameters

pool

A mongoc_client_pool_t.

client

A mongoc_client_t.

libmongoc-1.3.1/doc/mongoc_client_pool_set_ssl_opts.page000066400000000000000000000036531264720626300235610ustar00rootroot00000000000000 mongoc_client_pool_set_ssl_opts()
Synopsis

This function is identical to mongoc_client_set_ssl_opts() except for client pools. It ensures that all clients retrieved from mongoc_client_pool_pop() or mongoc_client_pool_try_pop() are configured with the same SSL settings.

It is a programming error to call this function after retrieving a client from the client pool.

Beginning in version 1.2.0, once a pool has any SSL options set, all connections use SSL, even if "ssl=true" is omitted from the MongoDB URI. Before, SSL options were ignored unless "ssl=true" was included in the URI.

Parameters

pool

A mongoc_client_pool_t.

opts

A mongoc_ssl_opt_t that will not be modified.

Availability

This feature requires that the MongoDB C driver was compiled with --enable-ssl.

libmongoc-1.3.1/doc/mongoc_client_pool_t.page000066400000000000000000000042311264720626300212740ustar00rootroot00000000000000 mongoc_client_pool_t Connection pooling abstraction
Synopsis

mongoc_client_pool_t is the basis for multi-threading in the MongoDB C driver. Since mongoc_client_t structures are not thread-safe, this structure is used to retrieve a new mongoc_client_t for a given thread. This structure is thread-safe.

Example static void * worker (void *data) { mongoc_client_pool_t *pool = data; mongoc_client_t *client; do { client = mongoc_client_pool_pop (pool); /* * Do something with client. If you are writing an HTTP server, you * probably only want to hold onto the client for the portion of the * request performing database queries. */ mongoc_client_pool_push (pool, client); } while (!inShutdown); return NULL; } int main (int argc, char *argv[]) { mongoc_client_pool_t *pool; mongoc_uri_t *uri; pthread_t thread[10]; unsigned i; void *ret; mongoc_init (); uri = mongoc_uri_new ("mongodb://mdb1.example.com/?minPoolSize=16"); pool = mongoc_client_pool_new (uri); for (i = 0; i < 10; i++) { pthread_create (&thread, NULL, worker, pool); } mongoc_uri_destroy (uri); for (i = 0; i < 10; i++) { pthread_join (threads [i], &ret); } mongoc_cleanup (); return 0; }]]>
Functions
libmongoc-1.3.1/doc/mongoc_client_pool_try_pop.page000066400000000000000000000023261264720626300225300ustar00rootroot00000000000000 mongoc_client_pool_try_pop()
Synopsis

This function is identical to mongoc_client_pool_pop() except it will return NULL instead of blocking for a client to become available.

Parameters

pool

A mongoc_client_pool_t.

Returns

A mongoc_client_t if one is immediately available, otherwise NULL.

libmongoc-1.3.1/doc/mongoc_client_set_read_concern.page000066400000000000000000000030761264720626300233030ustar00rootroot00000000000000 mongoc_client_set_read_concern()
Synopsis

Sets the read concern for the client. This only affects future operations, collections, and databases inheriting from client.

The default read concern is MONGOC_READ_CONCERN_LEVEL_LOCAL. This is the correct read concern for the great majority of applications.

It is a programming error to call this function on a client from a mongoc_client_pool_t. For pooled clients, set the read concern with the MongoDB URI instead.

Parameters

client

A mongoc_client_t.

read_concern

A mongoc_read_concern_t.

libmongoc-1.3.1/doc/mongoc_client_set_read_prefs.page000066400000000000000000000031061264720626300227650ustar00rootroot00000000000000 mongoc_client_set_read_prefs()
Synopsis

Sets the default read preferences to use with future operations upon client.

The global default is to read from the replica set primary.

It is a programming error to call this function on a client from a mongoc_client_pool_t. For pooled clients, set the read preferences with the MongoDB URI instead.

Please see the MongoDB website for a description of Read Preferences.

Parameters

client

A mongoc_client_t.

read_prefs

A mongoc_read_prefs_t.

libmongoc-1.3.1/doc/mongoc_client_set_ssl_opts.page000066400000000000000000000042161264720626300225240ustar00rootroot00000000000000 mongoc_client_set_ssl_opts()
Synopsis

Sets the SSL options to use when connecting to SSL enabled MongoDB servers.

Beginning in version 1.2.0, once a client has any SSL options set, all connections use SSL, even if "ssl=true" is omitted from the MongoDB URI. Before, SSL options were ignored unless "ssl=true" was included in the URI.

Although the mongoc_ssl_opt_t struct itself is shallow-copied by the client, the strings it points to (pem_file, pem_pwd, ca_file, ca_dir, and crl_file) are not copied and must remain valid for the life of the mongoc_client_t.

It is a programming error to call this function on a client from a mongoc_client_pool_t. Instead, call mongoc_client_pool_set_ssl_opts on the pool before popping any clients.

Parameters

client

A mongoc_client_t.

opts

A mongoc_ssl_opt_t. The struct is copied by the client, but the strings it points to are not.

Availability

This feature requires that the MongoDB C driver was compiled with --enable-ssl.

libmongoc-1.3.1/doc/mongoc_client_set_stream_initiator.page000066400000000000000000000033571264720626300242400ustar00rootroot00000000000000 mongoc_client_set_stream_initiator()
Synopsis

The mongoc_client_set_stream_initiator() function shall associate a given mongoc_client_t with a new stream initiator. This will completely replace the default transport (buffered TCP, possibly with TLS). The initiator should fulfill the mongoc_stream_t contract. user_data is passed through to the initiator callback and may be used for whatever run time customization is necessary.

Parameters

client

A mongoc_client_t.

initiator

A mongoc_stream_initiator_t.

user_data

User supplied pointer for callback function.

libmongoc-1.3.1/doc/mongoc_client_set_write_concern.page000066400000000000000000000032341264720626300235160ustar00rootroot00000000000000 mongoc_client_set_write_concern()
Synopsis

Sets the write concern for the client. This only affects future operations, collections, and databases inheriting from client.

The default write concern is MONGOC_WRITE_CONCERN_W_DEFAULT: the driver blocks awaiting basic acknowledgment of write operations from MongoDB. This is the correct write concern for the great majority of applications.

It is a programming error to call this function on a client from a mongoc_client_pool_t. For pooled clients, set the write concern with the MongoDB URI instead.

Parameters

client

A mongoc_client_t.

write_concern

A mongoc_write_concern_t.

libmongoc-1.3.1/doc/mongoc_client_t.page000066400000000000000000000053601264720626300202470ustar00rootroot00000000000000 mongoc_client_t MongoDB Connection Abstraction
Synopsis

mongoc_client_t is an opaque type that provides access to a MongoDB node, replica-set, or sharded-cluster. It maintains management of underlying sockets and routing to individual nodes based on mongoc_read_prefs_t or mongoc_write_concern_t.

Streams

The underlying transport for a given client can be customized, wrapped or replaced by any implementation that fulfills mongoc_stream_t. A custom transport can be set with mongoc_client_set_stream_initiator().

Thread Safety

mongoc_client_t is NOT thread-safe and should only be used from one thread at a time. When used in multi-threaded scenarios, it is recommended that you use the thread-safe mongoc_client_pool_t to retrieve a mongoc_client_t for your thread.

Lifecycle

It is an error to call mongoc_client_destroy on a client that has operations pending. It is required that you release mongoc_collection_t and mongoc_database_t structures before calling mongoc_client_destroy.

Example
Functions
libmongoc-1.3.1/doc/mongoc_collection_aggregate.page000066400000000000000000000116451264720626300226120ustar00rootroot00000000000000 mongoc_collection_aggregate()
Synopsis
Parameters

collection

A mongoc_collection_t.

flags

A mongoc_query_flags_t.

pipeline

A bson_t containing the pipeline array.

options

A bson_t containing options for the pipeline, or NULL.

read_prefs

A mongoc_read_prefs_t or NULL.

Description

This function shall execute an aggregation query on the underlying 'collection'. The bson 'pipeline' is not validated, simply passed along as appropriate to the server. As such, compatibility and errors should be validated in the appropriate server documentation.

In the case of older server versions, < v2.5, the returned cursor is a synthetic iterator over the result set. This provides a limitation insofar as returned documents can be no larger than 16MB. When connecting to newer servers this limitation doesn't exist. The specific test is for wire_version > 0.

For more information on building MongoDB pipelines, see MongoDB Aggregation Command on the MongoDB website.

The pipeline parameter should contain a field named pipeline containing a BSON array of pipeline stages.

The mongoc_read_concern_t specified on the mongoc_collection_t will be used, if any.

Returns

This function returns a newly allocated mongoc_cursor_t that should be freed with mongoc_cursor_destroy() when no longer in use. NULL may be returned if parameters are invalid.

Failure to handle the result of this function is a programming error.

Example Aggregation Example #include static mongoc_cursor_t * pipeline_query (mongoc_collection_t *collection) { mongoc_cursor_t *cursor; bson_t *pipeline; pipeline = BCON_NEW ("pipeline", "[", "{", "$match", "{", "foo", BCON_UTF8 ("A"), "}", "}", "{", "$match", "{", "bar", BCON_BOOL (false), "}", "}", "]"); cursor = mongoc_collection_aggregate (collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL); bson_destroy (pipeline); return cursor; }]]>
Other Parameters

Pass any parameters to the aggregate command, besides pipeline, as fields in options:

libmongoc-1.3.1/doc/mongoc_collection_command.page000066400000000000000000000056731264720626300223060ustar00rootroot00000000000000 mongoc_collection_command()
Synopsis
Parameters

collection

A mongoc_collection_t.

flags

A mongoc_query_flags_t.

skip

A uint32_t with the number of documents to skip or zero.

limit

A uint32_t with the max number of documents to return or zero.

batch_size

A uint32_t with the number of documents in each batch or zero. Default is 100.

command

A bson_t containing the command to execute.

fields

A bson_t containing the fields to return or NULL. Not all commands support this option.

read_prefs

A mongoc_read_prefs_t or NULL.

Description

This function shall execute a command on a collection. This is performed lazily and therefore requires calling mongoc_cursor_next() on the resulting cursor structure. The cursor should be freed with mongoc_cursor_destroy() when no longer in use.

Returns

A lazy mongoc_cursor_t that should be freed with mongoc_cursor_destroy().

Failure to handle the result of this function is a programming error.

libmongoc-1.3.1/doc/mongoc_collection_command_simple.page000066400000000000000000000067761264720626300236640ustar00rootroot00000000000000 mongoc_collection_command_simple()
Synopsis
Parameters

collection

A mongoc_collection_t.

command

A bson_t containing the command to execute.

read_prefs

A mongoc_read_prefs_t or NULL.

reply

A location to initialize a bson_t. This should be on the stack.

error

An optional location for a bson_error_t or NULL.

Description

This is a simplified version of mongoc_collection_command() that returns the first result document in reply. The parameter reply is initialized even upon failure to simplify memory management.

This function tries to unwrap an embedded error in the command when possible. The unwrapped error will be propagated via the error parameter. Additionally, the result document is set in reply.

Errors

Errors are propagated via the error parameter.

Returns

true if successful, otherwise false.

Not all commands have truly succeeded when {ok:1.0} is returned. This could simply mean the RPC successfully was executed.

Example

The following is an example of executing the collection stats command.

Command Example #include #include static void print_collection_stats (mongoc_collection_t *collection) { bson_error_t error; const char *name; bson_t *cmd; bson_t reply; name = mongoc_collection_get_name (collection); cmd = BCON_NEW ("collStats", BCON_UTF8 (name)); if (mongoc_collection_command_simple (collection, cmd, NULL, &reply, &error)) { str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); } else { fprintf (stderr, "%s\n", error.message); } bson_destroy (&reply); bson_destroy (cmd); } ]]>
libmongoc-1.3.1/doc/mongoc_collection_copy.page000066400000000000000000000035461264720626300216370ustar00rootroot00000000000000 mongoc_collection_copy()
Synopsis
Parameters

collection

A mongoc_collection_t.

Description

Performs a deep copy of the collection struct and its configuration. Useful if you intend to call mongoc_collection_set_write_concern, mongoc_collection_set_read_prefs, or mongoc_collection_set_read_concern, and want to preserve an unaltered copy of the struct.

This function does not copy the contents of the collection on the MongoDB server; use the cloneCollection command for that purpose.

Returns

A newly allocated mongoc_collection_t that should be freed with mongoc_collection_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_collection_count.page000066400000000000000000000066451264720626300220200ustar00rootroot00000000000000 mongoc_collection_count()
Synopsis
Parameters

collection

A mongoc_collection_t.

flags

A mongoc_query_flags_t.

query

A bson_t containing the query.

skip

A int64_t, zero to ignore.

limit

A int64_t, zero to ignore.

read_prefs

A mongoc_read_prefs_t or NULL.

error

An optional location for a bson_error_t or NULL.

Description

This function shall execute a count query on the underlying 'collection'. The bson 'query' is not validated, simply passed along as appropriate to the server. As such, compatibility and errors should be validated in the appropriate server documentation.

For more information, see the query reference at the MongoDB website.

The mongoc_read_concern_t specified on the mongoc_collection_t will be used, if any.

Errors

Errors are propagated via the error parameter.

Returns

-1 on failure, otherwise the number of documents counted.

Example Count Example #include #include static void print_query_count (mongoc_collection_t *collection, bson_t *query) { bson_error_t error; int64_t count; count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, query, 0, 0, NULL, &error); if (count < 0) { fprintf (stderr, "Count failed: %s\n", error.message); } else { printf ("%"PRId64" documents counted.\n", count); } }]]>
libmongoc-1.3.1/doc/mongoc_collection_count_with_opts.page000066400000000000000000000100361264720626300241050ustar00rootroot00000000000000 mongoc_collection_count_with_opts()
Synopsis
Parameters

collection

A mongoc_collection_t.

flags

A mongoc_query_flags_t.

query

A bson_t containing the query.

skip

A int64_t, zero to ignore.

limit

A int64_t, zero to ignore.

opts

A bson_t, NULL to ignore.

read_prefs

A mongoc_read_prefs_t or NULL.

error

An optional location for a bson_error_t or NULL.

Description

This function shall execute a count query on the underlying 'collection'. The bson 'query' is not validated, simply passed along as appropriate to the server. As such, compatibility and errors should be validated in the appropriate server documentation.

In addition to the standard functionality available from mongoc_collection_count, this function allows the user to add arbitrary extra keys to the count. This pass through enables features such as hinting for counts.

For more information, see the query reference at the MongoDB website.

The mongoc_read_concern_t specified on the mongoc_collection_t will be used, if any.

Errors

Errors are propagated via the error parameter.

Returns

-1 on failure, otherwise the number of documents counted.

Example Count Example #include #include static void print_query_count (mongoc_collection_t *collection, bson_t *query) { bson_error_t error; int64_t count; bson_t opts; bson_init(&opts); BSON_APPEND_UTF8(&opts, "hint", "_id_"); count = mongoc_collection_count_with_opts (collection, MONGOC_QUERY_NONE, query, 0, 0, &opts, NULL, &error); bson_destroy(&opts); if (count < 0) { fprintf (stderr, "Count failed: %s\n", error.message); } else { printf ("%"PRId64" documents counted.\n", count); } }]]>
libmongoc-1.3.1/doc/mongoc_collection_create_bulk_operation.page000066400000000000000000000054611264720626300252230ustar00rootroot00000000000000 mongoc_collection_create_bulk_operation()
Synopsis
Parameters

collection

A mongoc_collection_t.

ordered

If the operations must be performed in order.

write_concern

An optional mongoc_write_concern_t or NULL.

Description

This function shall begin a new bulk operation. After creating this you may call various functions such as mongoc_bulk_operation_update(), mongoc_bulk_operation_insert() and others.

After calling mongoc_bulk_operation_execute() the commands will be executed in as large as batches as reasonable by the client.

If ordered is true, then processing will stop at the first error.

If ordered is not true, then the bulk operation will attempt to continue processing even after the first failure.

write_concern contains the write concern for all operations in the bulk operation. If NULL, the collection's write concern is used. The global default is acknowledged writes: MONGOC_WRITE_CONCERN_W_DEFAULT.

Errors

Errors are propagated when executing the bulk operation.

Returns

A newly allocated mongoc_bulk_operation_t that should be freed with mongoc_bulk_operation_destroy() when no longer in use.

Failure to handle the result of this function is a programming error.

libmongoc-1.3.1/doc/mongoc_collection_create_index.page000066400000000000000000000040441264720626300233110ustar00rootroot00000000000000 mongoc_collection_create_index()
Synopsis
Parameters

collection

A mongoc_collection_t.

keys

A bson_t.

opt

A mongoc_index_opt_t.

error

An optional location for a bson_error_t or NULL.

Description

This function will request the creation of a new index.

This function will use the createIndexes command if available on the MongoDB server. If not, it will fallback to inserting into system.indexes for compatibility with MongoDB <= 2.4.

See mongoc_index_opt_t for options on creating indexes.

Errors

Errors are propagated via the error parameter.

Returns

true on success, false on failure and error is set.

libmongoc-1.3.1/doc/mongoc_collection_delete.page000066400000000000000000000052471264720626300221270ustar00rootroot00000000000000 mongoc_collection_delete()
Synopsis
Deprecated

This function is deprecated and should not be used in new code.

Please use mongoc_collection_remove() instead.

Parameters

collection

A mongoc_collection_t.

flags

A mongoc_delete_flags_t.

selector

A bson_t containing the query to match documents.

write_concern

A mongoc_write_concern_t or NULL.

error

An optional location for a bson_error_t or NULL.

Description

This function shall delete documents in the given collection that match selector. The bson selector is not validated, simply passed along as appropriate to the server. As such, compatibility and errors should be validated in the appropriate server documentation.

If you want to limit deletes to a single document, provide MONGOC_DELETE_SINGLE_REMOVE in flags.

Errors

Errors are propagated via the error parameter.

Returns

true if successful, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_collection_destroy.page000066400000000000000000000022711264720626300223500ustar00rootroot00000000000000 mongoc_collection_destroy()
Synopsis
Parameters

collection

A mongoc_collection_t.

Description

This function shall destroy a mongoc_collection_t and its associated resources.

Always destroy a mongoc_cursor_t created from a collection before destroying the collection.

libmongoc-1.3.1/doc/mongoc_collection_drop.page000066400000000000000000000030201264720626300216140ustar00rootroot00000000000000 mongoc_collection_drop()
Synopsis
Parameters

collection

A mongoc_collection_t.

error

An optional location for a bson_error_t or NULL.

Description

This function requests that a collection be dropped, including all indexes associated with the collection.

Errors

Errors are propagated via the error parameter.

Returns

Returns true if the collection was successfully dropped. Otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_collection_drop_index.page000066400000000000000000000032441264720626300230130ustar00rootroot00000000000000 mongoc_collection_drop_index()
Synopsis
Parameters

collection

A mongoc_collection_t.

index_name

A string containing the name of the index.

error

An optional location for a bson_error_t or NULL.

Description

This function requests than an index on collection be dropped. In the event of an error it returns false and error is set.

Errors

Errors are propagated via the error parameter.

Returns

true if successful, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_collection_ensure_index.page000066400000000000000000000034741264720626300233550ustar00rootroot00000000000000 mongoc_collection_ensure_index()
Synopsis
Deprecated

This function is deprecated and should not be used in new code.

Please use mongoc_collection_create_index() instead.

Parameters

collection

A mongoc_collection_t.

keys

A bson_t.

opt

A mongoc_index_opt_t.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

libmongoc-1.3.1/doc/mongoc_collection_find.page000066400000000000000000000222441264720626300216010ustar00rootroot00000000000000 mongoc_collection_find()
Synopsis
Parameters

collection

A mongoc_collection_t.

flags

A mongoc_query_flags_t.

skip

A uint32_t of number of documents to skip or 0.

limit

A uint32_t of max number of documents to return or 0.

batch_size

A uint32_t containing batch size of document result sets or 0 for default. Default is 100.

query

A bson_t containing the query and options to execute.

fields

A bson_t containing fields to return or NULL.

read_prefs

A mongoc_read_prefs_t or NULL for default read preferences.

Description

This function shall execute a query on the underlying collection.

If no options are necessary, query can simply contain a query such as {a:1}. If you would like to specify options such as a sort order, the query must be placed inside of {"$query": {}} as specified by the server documentation. See the example below for how to properly specify additional options to query.

Returns

A newly allocated mongoc_cursor_t that should be freed with mongoc_cursor_destroy() when no longer in use. If invalid parameters are supplied, NULL may be returned.

Failure to handle the result of this function is a programming error.

Example Print All Documents in a Collection #include static void print_all_documents (mongoc_collection_t *collection) { mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; char *str; bson_t *query; query = BCON_NEW ("$query", "{", "foo", BCON_INT32 (1), "}", "$orderby", "{", "bar", BCON_INT32 (-1), "}"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL); while (mongoc_cursor_more (cursor) && mongoc_cursor_next (cursor, &doc)) { str = bson_as_json (doc, NULL); printf ("%s\n", str); bson_free (str); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "An error occurred: %s\n", error.message); } mongoc_cursor_destroy (cursor); bson_destroy (query); } ]]>
The "find" command

Queries have historically been sent as OP_QUERY wire protocol messages, but beginning in MongoDB 3.2 queries use the "find" command instead.

The driver automatically converts queries to the new "find" command syntax if needed, so this change is typically invisible to C Driver users. However, an application written exclusively for MongoDB 3.2 and later can choose to use the new syntax directly instead of relying on the driver to convert from the old syntax:

The "find" command takes different options from the traditional OP_QUERY message.

Option

OP_QUERY option

"find" command option

Query

$query

filter

Sort

$orderby

sort

Show record location

$showDiskLoc

showRecordId

Other $-options

$<option name>

<option name>

Most applications should use the OP_QUERY syntax, with "$query", "$orderby", and so on, and rely on the driver to convert to the new syntax if needed. There are two caveats: querying documents by a key named "filter", and using new "find" command options that OP_QUERY does not support.

See Also

The "find" command in the MongoDB Manual.

Finding a document by a key named "filter"

To find a document like { "_id": 1, "filter": "value" }, this query works in MongoDB before 3.2:

Beginning in MongoDB 3.2, the "filter" option has special meaning, and it is no longer assumed to be a field in a document you are querying for. To execute this query on any MongoDB version, wrap it in "$query":

This code works for any MongoDB version. The driver sends it as-is to a MongoDB server older than 3.2, and before sending to MongoDB 3.2 or later converts it to the following:

{ "filter": { "filter": "value" } }
Options specific to the "find" command

The "find" command has new options like "singleBatch" not supported by OP_QUERY. Applications should use the new "find" syntax directly to take advantage of them:

The "explain" command

With MongoDB before 3.2, a query with option $explain: true returns information about the query plan, instead of the query results. Beginning in MongoDB 3.2, there is a separate "explain" command. The driver will not convert "$explain" queries to "explain" commands, you must call the "explain" command explicitly:

See Also

The "explain" command in the MongoDB Manual.

libmongoc-1.3.1/doc/mongoc_collection_find_and_modify.page000066400000000000000000000072051264720626300237720ustar00rootroot00000000000000 mongoc_collection_find_and_modify()
Synopsis
Parameters

collection

A mongoc_collection_t.

query

A bson_t containing the query to locate target document(s).

sort

A bson_t containing the sort order for query.

update

A bson_t containing an update spec.

fields

An optional bson_t containing the fields to return or NULL.

_remove

If the matching documents should be removed.

upsert

If an upsert should be performed.

_new

If the new version of the document should be returned.

reply

An optional location for a bson_t that will be initialized with the result or NULL.

error

An optional location for a bson_error_t or NULL.

Description

Update and return an object.

This is a thin wrapper around the findAndModify command. Either update or _remove arguments are required.

As of MongoDB 3.2 and mongoc 1.3.0, the mongoc_write_concern_t specified on the mongoc_collection_t will be used, if any.

Errors

Errors are propagated via the error parameter.

Returns

Returns either the document before or after modification based on the _new parameter.

Example <file>find-and-modify.c</file>
libmongoc-1.3.1/doc/mongoc_collection_find_and_modify_with_opts.page000066400000000000000000000046141264720626300260730ustar00rootroot00000000000000 mongoc_collection_find_and_modify_with_opts()
Synopsis

New in mongoc 1.3.0

Parameters

collection

A mongoc_collection_t.

query

A bson_t containing the query to locate target document(s).

opts

find and modify options

reply

An optional location for a bson_t that will be initialized with the result or NULL.

error

An optional location for a bson_error_t or NULL.

Description

Update and return an object.

Errors

Errors are propagated via the error parameter.

Returns

Returns true on success; false on failure.

Example

See mongoc_find_and_modify_opts_t

libmongoc-1.3.1/doc/mongoc_collection_find_indexes.page000066400000000000000000000030431264720626300233140ustar00rootroot00000000000000 mongoc_collection_find_indexes()
Synopsis

Fetches a cursor containing documents, each corresponding to an index on this collection.

Parameters

collection

A mongoc_collection_t.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

A cursor where each result corresponds to the server's representation of an index on this collection. If the collection does not exist on the server, the cursor will be empty.

libmongoc-1.3.1/doc/mongoc_collection_get_last_error.page000066400000000000000000000026031264720626300236710ustar00rootroot00000000000000 mongoc_collection_get_last_error()
Synopsis
Parameters

collection

A mongoc_collection_t.

Description

The mongoc_collection_get_last_error() function shall return getLastError document, according to write_concern on last executed command for current collection instance.

A write_concern must be at least MONGOC_WRITE_CONCERN_W_DEFAULT in last command execution for this to be available.

Returns

A bson_t that should not be modified or NULL.

libmongoc-1.3.1/doc/mongoc_collection_get_name.page000066400000000000000000000021111264720626300224270ustar00rootroot00000000000000 mongoc_collection_get_name()
Synopsis
Parameters

collection

A mongoc_collection_t.

Description

Fetches the name of collection.

Returns

A string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_collection_get_read_concern.page000066400000000000000000000023541264720626300241420ustar00rootroot00000000000000 mongoc_collection_get_read_concern()
Synopsis
Parameters

collection

A mongoc_collection_t.

Description

Fetches the default read concern to be used on read operations originating from collection.

Returns

A mongoc_read_concern_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_collection_get_read_prefs.page000066400000000000000000000024051264720626300236270ustar00rootroot00000000000000 mongoc_collection_get_read_prefs()
Synopsis
Parameters

collection

A mongoc_collection_t.

Description

Fetches the default read preferences to use for collection. Operations without specified read-preferences will default to this.

Returns

A mongoc_read_prefs_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_collection_get_write_concern.page000066400000000000000000000024271264720626300243620ustar00rootroot00000000000000 mongoc_collection_get_write_concern()
Synopsis
Parameters

collection

A mongoc_collection_t.

Description

Fetches the default write concern to be used on write operations originating from collection and not specifying a write concern.

Returns

A mongoc_write_concern_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_collection_insert.page000066400000000000000000000045431264720626300221670ustar00rootroot00000000000000 mongoc_collection_insert()
Synopsis
Parameters

collection

A mongoc_collection_t.

flags

A mongoc_insert_flags_t.

document

A bson_t.

write_concern

A mongoc_write_concern_t.

error

An optional location for a bson_error_t or NULL.

Description

This function shall insert document into collection.

If no _id element is found in document, then a bson_oid_t will be generated locally and added to the document.

You can retrieve a generated _id from mongoc_collection_get_last_error().

Errors

Errors are propagated via the error parameter.

Returns

true if the document was successfully inserted, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_collection_insert_bulk.page000066400000000000000000000053261264720626300232040ustar00rootroot00000000000000 mongoc_collection_insert_bulk()
Synopsis
Deprecated

This function is deprecated and should not be used in new code.

Please use mongoc_collection_create_bulk_operation() instead.

Parameters

collection

A mongoc_collection_t.

flags

A bitwise or of mongoc_insert_flags_t.

documents

An array of const bson_t *.

n_documents

The number of documents in documents.

write_concern

A mongoc_write_concern_t or NULL.

error

An optional location for a bson_error_t or NULL.

Description

This function performs a bulk insert of all of the documents in documents. This function is deprecated as it cannot accurately return which documents may have failed during the bulk insert.

Errors

Errors are propagated via the error parameter.

Returns

true if successful, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_collection_keys_to_index_string.page000066400000000000000000000026401264720626300251110ustar00rootroot00000000000000 mongoc_collection_keys_to_index_string()
Synopsis
Parameters

keys

A bson_t.

Description

This function shall returns the canonical stringification, as used in mongoc_collection_create_index() without an explicit name, of a given key specification.

It is a programming error to call this function on a non-standard index, such one other than a straight index with ascending and descending.

Returns

A string that should be freed with bson_free().

libmongoc-1.3.1/doc/mongoc_collection_remove.page000066400000000000000000000046201264720626300221540ustar00rootroot00000000000000 mongoc_collection_remove()
Synopsis
Parameters

collection

A mongoc_collection_t.

flags

A mongoc_remove_flags_t.

selector

A bson_t containing the query to match documents.

write_concern

A mongoc_write_concern_t or NULL.

error

An optional location for a bson_error_t or NULL.

Description

This function shall remove documents in the given collection that match selector. The bson selector is not validated, simply passed along as appropriate to the server. As such, compatibility and errors should be validated in the appropriate server documentation.

If you want to limit deletes to a single document, provide MONGOC_REMOVE_SINGLE_REMOVE in flags.

Errors

Errors are propagated via the error parameter.

Returns

true if successful, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_collection_rename.page000066400000000000000000000041761264720626300221340ustar00rootroot00000000000000 mongoc_collection_rename()
Synopsis
Parameters

collection

A mongoc_collection_t.

new_db

The name of the new database.

new_name

The new name for the collection.

drop_target_before_rename

If an existing collection matches the new name, drop it before the rename.

error

An optional location for a bson_error_t or NULL.

Description

This function is a helper to rename an existing collection on a MongoDB server. The name of the collection will also be updated internally so it is safe to continue using this collection after the rename. Additional operations will occur on renamed collection.

Errors

Errors are propagated via the error parameter.

Returns

true if the command executed successfully, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_collection_save.page000066400000000000000000000037041264720626300216170ustar00rootroot00000000000000 mongoc_collection_save()
Synopsis
Parameters

collection

A mongoc_collection_t.

document

A bson_t containing the document.

write_concern

A mongoc_write_concern_t or NULL for default write concern.

error

An optional location for a bson_error_t or NULL.

Description

This function shall save a document into collection. If the document has an _id field it will be updated. Otherwise it will be inserted.

Errors

Errors are propagated via the error parameter.

Returns

true if successful, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_collection_set_read_concern.page000066400000000000000000000025001264720626300241470ustar00rootroot00000000000000 mongoc_collection_set_read_concern()
Synopsis
Parameters

collection

A mongoc_collection_t.

read_concern

A mongoc_read_concern_t.

Description

Sets the read concern to use for operations on collection.

The default read concern is empty: No readConcern is sent to the server unless explicitly configured.

libmongoc-1.3.1/doc/mongoc_collection_set_read_prefs.page000066400000000000000000000030561264720626300236460ustar00rootroot00000000000000 mongoc_collection_set_read_prefs()
Synopsis
Parameters

collection

A mongoc_collection_t.

read_prefs

A mongoc_read_prefs_t.

Description

Sets the default read preferences to use for operations on collection not specifying a read preference.

The global default is MONGOC_READ_PRIMARY: if the client is connected to a replica set it reads from the primary, otherwise it reads from the current MongoDB server.

Please see the MongoDB website for a description of Read Preferences.

libmongoc-1.3.1/doc/mongoc_collection_set_write_concern.page000066400000000000000000000026741264720626300244020ustar00rootroot00000000000000 mongoc_collection_set_write_concern()
Synopsis
Parameters

collection

A mongoc_collection_t.

write_concern

A mongoc_write_concern_t.

Description

Sets the write concern to use for operations on collection.

The default write concern is MONGOC_WRITE_CONCERN_W_DEFAULT: the driver blocks awaiting basic acknowledgment of write operations from MongoDB. This is the correct write concern for the great majority of applications.

libmongoc-1.3.1/doc/mongoc_collection_stats.page000066400000000000000000000036021264720626300220140ustar00rootroot00000000000000 mongoc_collection_stats()
Synopsis
Parameters

collection

A mongoc_collection_t.

options

An optional bson_t containing extra options to pass to the collStats command.

reply

An optional location for a bson_t to store the result.

error

An optional location for a bson_error_t or NULL.

Description

This function is a helper to retrieve statistics about the collection.

Errors

Errors are propagated via the error parameter.

Returns

true if successful

reply is always initialized to simplfiy memory handling.

libmongoc-1.3.1/doc/mongoc_collection_t.page000066400000000000000000000027271264720626300211300ustar00rootroot00000000000000 mongoc_collection_t
Synopsis typedef struct _mongoc_collection_t mongoc_collection_t;]]>

mongoc_collection_t provides access to a MongoDB collection. This handle is useful for actions for most CRUD operations, I.e. insert, update, delete, find, etc.

Read Preferences and Write Concerns

Read preferences and write concerns are inherited from the parent client. They can be overridden by set_* commands if so desired.

Lifecycle

It is an error to call mongoc_collection_destroy() on a collection that has operations pending. It is required that you release mongoc_cursor_t structures before calling mongoc_collection_destroy().

Functions
libmongoc-1.3.1/doc/mongoc_collection_update.page000066400000000000000000000046131264720626300221430ustar00rootroot00000000000000 mongoc_collection_update()
Synopsis
Parameters

collection

A mongoc_collection_t.

flags

A bitwise or of mongoc_update_flags_t.

selector

A bson_t containing the query to match documents for updating.

update

A bson_t containing the update to perform.

write_concern

A mongoc_write_concern_t.

error

An optional location for a bson_error_t or NULL.

Description

This function shall update documents in collection that match selector.

By default, updates only a single document. Set flags to MONGOC_UPDATE_MULTI_UPDATE to update multiple documents.

Errors

Errors are propagated via the error parameter.

Returns

true if successful, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_collection_validate.page000066400000000000000000000041001264720626300224410ustar00rootroot00000000000000 mongoc_collection_validate()
Synopsis
Parameters

collection

A mongoc_collection_t.

options

A bson_t.

reply

A bson_t.

error

An optional location for a bson_error_t or NULL.

Description

This function is a helper function to execute the validate MongoDB command.

Currently, the only supported options are full, which is a boolean and scandata, also a boolean.

See the MongoDB documentation for more information on this command.

Errors

Errors are propagated via the error parameter.

Returns

true if successful, otherwise false and error is set.

reply is always initialized and must be destroyed with bson_destroy().

libmongoc-1.3.1/doc/mongoc_cursor_clone.page000066400000000000000000000030721264720626300211410ustar00rootroot00000000000000 mongoc_cursor_clone()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

Description

This function shall create a copy of a mongoc_cursor_t. The cloned cursor will be reset to the beginning of the query, and therefore the query will be re-executed on the MongoDB server when mongoc_cursor_next() is called.

Returns

A newly allocated mongoc_cursor_t that should be freed with mongoc_cursor_destroy() when no longer in use.

Failure to handle the result of this function is a programming error.

libmongoc-1.3.1/doc/mongoc_cursor_current.page000066400000000000000000000022071264720626300215220ustar00rootroot00000000000000 mongoc_cursor_current()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

Description

Fetches the cursors current document or NULL if there has been an error.

Returns

A bson_t that should not be modified or freed or NULL.

libmongoc-1.3.1/doc/mongoc_cursor_destroy.page000066400000000000000000000020351264720626300215300ustar00rootroot00000000000000 mongoc_cursor_destroy()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

Description

Frees a mongoc_cursor_t and releases all associated resources. If a server-side cursor has been allocated, it will be released as well.

libmongoc-1.3.1/doc/mongoc_cursor_error.page000066400000000000000000000026251264720626300211750ustar00rootroot00000000000000 mongoc_cursor_error()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

error

An optional location for a bson_error_t or NULL.

Description

This function checks to see if an error has occurred while iterating the cursor.

Errors

Errors are propagated via the error parameter.

Returns

false if no error has occurred, otherwise true and error is set.

libmongoc-1.3.1/doc/mongoc_cursor_get_host.page000066400000000000000000000022001264720626300216450ustar00rootroot00000000000000 mongoc_cursor_get_host()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

host

A mongoc_host_list_t.

Description

Fetches the MongoDB host that the cursor is communicating with in the host out parameter.

libmongoc-1.3.1/doc/mongoc_cursor_get_max_await_time_ms.page000066400000000000000000000020301264720626300243600ustar00rootroot00000000000000 mongoc_cursor_get_max_await_time_ms()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

Description

Retrieve the value set with mongoc_cursor_set_max_await_time_ms.

libmongoc-1.3.1/doc/mongoc_cursor_is_alive.page000066400000000000000000000022261264720626300216340ustar00rootroot00000000000000 mongoc_cursor_is_alive()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

Description

Checks to see if a cursor is in a state that allows for more documents to be queried.

This is primarily useful with tailable cursors.

Returns

true if there may be more content to retrieve from the cursor.

libmongoc-1.3.1/doc/mongoc_cursor_more.page000066400000000000000000000021131264720626300207760ustar00rootroot00000000000000 mongoc_cursor_more()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

Description

This function shall indicate if there is more data to be read from the cursor.

Returns

true if there is more data to be read from the cursor, otherwise false.

libmongoc-1.3.1/doc/mongoc_cursor_next.page000066400000000000000000000034771264720626300210300ustar00rootroot00000000000000 mongoc_cursor_next()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

bson

A location for a const bson_t *.

Description

This function shall iterate the underlying cursor, setting bson to the next document.

This function is a blocking function.

Returns

This function returns true if a valid bson document was read from the cursor. Otherwise, false if there was an error or the cursor was exhausted.

Errors can be determined with the mongoc_cursor_error() function.

Lifecycle

The bson objects set in this function are ephemeral and good until the next call. This means that you must copy the returned bson if you wish to retain it beyond the lifetime of a single call to mongoc_cursor_next().

libmongoc-1.3.1/doc/mongoc_cursor_set_max_await_time_ms.page000066400000000000000000000035311264720626300244030ustar00rootroot00000000000000 mongoc_cursor_set_max_await_time_ms()
Synopsis
Parameters

cursor

A mongoc_cursor_t.

max_await_time_ms

A timeout in milliseconds.

Description

The maximum amount of time for the server to wait on new documents to satisfy a tailable cursor query. Only applies if the cursor is created from mongoc_collection_find with the query flags MONGOC_QUERY_TAILABLE_CURSOR and MONGOC_QUERY_AWAIT_DATA, and the server is MongoDB 3.2 or later. See the documentation for maxTimeMS and the "getMore" command.

The max_await_time_ms cannot be changed after the first call to mongoc_cursor_next.

See Also

Tailable Cursors.

libmongoc-1.3.1/doc/mongoc_cursor_t.page000066400000000000000000000041731264720626300203070ustar00rootroot00000000000000 mongoc_cursor_t Client-side cursor abtraction
Synopsis

mongoc_cursor_t provides access to a MongoDB query cursor. It wraps up the wire protocol negotiation required to initiate a query and retrieve an unknown number of documents. Cursors are lazy, meaning that no network traffic occurs until the first call to mongoc_cursor_next(). At that point we can:

Determine which host we've connected to with mongoc_cursor_get_host().

Retrieve more records with repeated calls to mongoc_cursor_next().

Test for more records with mongoc_cursor_more()

Clone a query to repeat execution at a later point with mongoc_cursor_clone().

Test for errors with mongoc_cursor_error().

Thread Safety

mongoc_cursor_t is NOT thread safe. It may only be used from the thread it was created from.

Example Query MongoDB and iterate results
Functions
libmongoc-1.3.1/doc/mongoc_database_add_user.page000066400000000000000000000044061264720626300220600ustar00rootroot00000000000000 mongoc_database_add_user()
Synopsis
Parameters

database

A mongoc_database_t.

username

The name of the user.

password

The cleartext password for the user.

roles

An optional bson_t for roles.

custom_data

A optional bson_t for extra data.

error

A location for a bson_error_t or NULL.

This function shall create a new user with access to database.

This function handles the difference between MongoDB 2.4 and 2.6.

Errors

Errors are returned through the error parameter and can include socket or other server side failures.

Returns

This function shall return true if the user was successfully added. In the event of an error, it returns false and error is set.

libmongoc-1.3.1/doc/mongoc_database_command.page000066400000000000000000000054261264720626300217130ustar00rootroot00000000000000 mongoc_database_command()
Synopsis
Parameters

database

A mongoc_database_t.

flags

A mongoc_query_flags_t.

skip

The number of documents to skip on the server.

limit

The maximum number of documents to return from the cursor.

batch_size

Attempt to batch results from the server in groups of batch_size documents.

command

A bson_t containing the command.

fields

An optional bson_t containing the fields to return. NULL for all fields.

read_prefs

An optional mongoc_read_prefs_t.

The mongoc_database_command() function shall execute a command on a database. This is performed lazily after calling mongoc_cursor_next() on the resulting cursor structure.

Returns

This command returns a mongoc_cursor_t that should be freed with mongoc_cursor_destroy() when no longer in use.

See Also

mongoc_cursor_next()

libmongoc-1.3.1/doc/mongoc_database_command_simple.page000066400000000000000000000044701264720626300232620ustar00rootroot00000000000000 mongoc_database_command_simple()
Synopsis
Parameters

database

A mongoc_database_t.

command

A bson_t containing the command.

read_prefs

An optional mongoc_read_prefs_t.

reply

A location to store the commands first result document.

error

An optional location for a bson_error_t or NULL.

This is a simplified interface to mongoc_database_command() that returns the first result document.

This function will always initialize reply. The caller should always call bson_destroy() with reply as an argument.

Errors

Errors are propagated through the error parameter.

Returns

true on success, false on failure and error is set.

libmongoc-1.3.1/doc/mongoc_database_copy.page000066400000000000000000000034501264720626300212420ustar00rootroot00000000000000 mongoc_database_copy()
Synopsis
Parameters

database

A mongoc_database_t.

Description

Performs a deep copy of the database struct and its configuration. Useful if you intend to call mongoc_database_set_write_concern, mongoc_database_set_read_prefs, or mongoc_database_set_read_concern, and want to preserve an unaltered copy of the struct.

This function does not copy the contents of the database on the MongoDB server; use the copydb command for that purpose.

Returns

A newly allocated mongoc_database_t that should be freed with mongoc_database_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_database_create_collection.page000066400000000000000000000034351264720626300237510ustar00rootroot00000000000000 mongoc_database_create_collection()
Synopsis
Parameters

database

A mongoc_database_t.

name

The name of the new collection.

options

An optional bson_t for options to the createDatabase command.

error

A location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

This function returns a newly allocated mongoc_collection_t upon success, NULL upon failure and error is set.

libmongoc-1.3.1/doc/mongoc_database_destroy.page000066400000000000000000000016361264720626300217650ustar00rootroot00000000000000 mongoc_database_destroy()
Synopsis

Releases all resources associated with database, including freeing the structure.

Parameters

database

A mongoc_database_t.

libmongoc-1.3.1/doc/mongoc_database_drop.page000066400000000000000000000025571264720626300212430ustar00rootroot00000000000000 mongoc_database_drop()
Synopsis

This function attempts to drop a database on the MongoDB server.

Parameters

database

A mongoc_database_t.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

true if successful, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_database_find_collections.page000066400000000000000000000032311264720626300236030ustar00rootroot00000000000000 mongoc_database_find_collections()
Synopsis

Fetches a cursor containing documents, each corresponding to a collection on this database.

Parameters

database

A mongoc_database_t.

filter

A matcher used by the server to filter the returned collections. May be NULL.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

A cursor where each result corresponds to the server's representation of a collection in this database.

libmongoc-1.3.1/doc/mongoc_database_get_collection.page000066400000000000000000000021421264720626300232570ustar00rootroot00000000000000 mongoc_database_get_collection()
Synopsis

Allocates a new mongoc_collection_t structure for the collection named name in database.

Returns

A newly allocated mongoc_collection_t that should be freed with mongoc_collection_destroy().

libmongoc-1.3.1/doc/mongoc_database_get_collection_names.page000066400000000000000000000042001264720626300244370ustar00rootroot00000000000000 mongoc_database_get_collection_names()
Synopsis

Fetches a NULL terminated array of NULL-byte terminated char* strings containing the names of all of the collections in database.

Parameters

database

A mongoc_database_t.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

A NULL terminated array of NULL terminated char* strings that should be freed with bson_strfreev(). Upon failure, NULL is returned and error is set.

Examples
libmongoc-1.3.1/doc/mongoc_database_get_name.page000066400000000000000000000017441264720626300220530ustar00rootroot00000000000000 mongoc_database_get_name()
Synopsis

Fetches the name of the database.

Parameters

database

A mongoc_database_t.

Returns

A string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_database_get_read_concern.page000066400000000000000000000023141264720626300235470ustar00rootroot00000000000000 mongoc_database_get_read_concern()
Synopsis

This function retrieves the default mongoc_read_concern_t to use with database as configured by the client.

Parameters

database

A mongoc_database_t.

Returns

A mongoc_read_concern_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_database_get_read_prefs.page000066400000000000000000000021531264720626300232400ustar00rootroot00000000000000 mongoc_database_get_read_prefs()
Synopsis

Fetches the default read preferences to use with database.

Parameters

database

A mongoc_database_t.

Returns

A mongoc_write_concern_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_database_get_write_concern.page000066400000000000000000000023241264720626300237670ustar00rootroot00000000000000 mongoc_database_get_write_concern()
Synopsis

This function retrieves the default mongoc_write_concern_t to use with database as configured by the client.

Parameters

database

A mongoc_database_t.

Returns

A mongoc_write_concern_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_database_has_collection.page000066400000000000000000000032061264720626300232550ustar00rootroot00000000000000 mongoc_database_has_collection()
Synopsis

This function checks to see if a collection exists on the MongoDB server within database.

Parameters

database

A mongoc_database_t.

name

A string containing the name of the collection.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

true is returned if the collection exists. false is returned if the collection does not exist or an error occurred.

libmongoc-1.3.1/doc/mongoc_database_remove_all_users.page000066400000000000000000000030261264720626300236350ustar00rootroot00000000000000 mongoc_database_remove_all_users()
Synopsis

This function will remove all users configured to access database.

Parameters

database

A mongoc_database_t.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter. This may fail if there are socket errors or the current user is not authorized to perform the given command.

Returns

true if successful, otherise false and error is set.

libmongoc-1.3.1/doc/mongoc_database_remove_user.page000066400000000000000000000032541264720626300226250ustar00rootroot00000000000000 mongoc_database_remove_user()
Synopsis

This function removes the user named username from database.

Parameters

database

A mongoc_database_t.

username

A string containing the username of the user to remove.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter. This could include socket errors or others if the current user is not authorized to perform the command.

Returns

true on success, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_database_set_read_concern.page000066400000000000000000000026331264720626300235670ustar00rootroot00000000000000 mongoc_database_set_read_concern()
Synopsis

This function sets the read concern to use on operations performed with database. Collections created with mongoc_database_get_collection() after this call will inherit this read concern.

The default read concern is empty: No readConcern is sent to the server unless explicitly configured.

Parameters

database

A mongoc_database_t.

read_concern

A mongoc_read_concern_t.

libmongoc-1.3.1/doc/mongoc_database_set_read_prefs.page000066400000000000000000000031551264720626300232570ustar00rootroot00000000000000 mongoc_database_set_read_prefs()
Synopsis

This function sets the default read preferences to use on operations performed with database. Collections created with mongoc_database_get_collection() after this call will inherit these read preferences.

The global default is MONGOC_READ_PRIMARY: if the client is connected to a replica set it reads from the primary, otherwise it reads from the current MongoDB server.

Please see the MongoDB website for a description of Read Preferences.

Parameters

database

A mongoc_database_t.

read_prefs

A mongoc_read_prefs_t.

libmongoc-1.3.1/doc/mongoc_database_set_write_concern.page000066400000000000000000000030301264720626300237760ustar00rootroot00000000000000 mongoc_database_set_write_concern()
Synopsis

This function sets the write concern to use on operations performed with database. Collections created with mongoc_database_get_collection() after this call will inherit this write concern.

The default write concern is MONGOC_WRITE_CONCERN_W_DEFAULT: the driver blocks awaiting basic acknowledgment of write operations from MongoDB. This is the correct write concern for the great majority of applications.

Parameters

database

A mongoc_database_t.

write_concern

A mongoc_write_concern_t.

libmongoc-1.3.1/doc/mongoc_database_t.page000066400000000000000000000041351264720626300205340ustar00rootroot00000000000000 mongoc_database_t MongoDB Database Abstraction
Synopsis

mongoc_database_t provides access to a MongoDB database. This handle is useful for actions a particular database object. It is not a container for mongoc_collection_t structures.

Read preferences and write concerns are inherited from the parent client. They can be overridden with mongoc_database_set_read_prefs() and mongoc_database_set_write_concern().

It is an error to call mongoc_database_destroy() on a database that has operations pending. It is required that you release mongoc_cursor_t structures before calling mongoc_database_destroy.

Functions
Examples int main (int argc, char *argv[]) { mongoc_database_t *database; mongoc_client_t *client; mongoc_init (); client = mongoc_client_new ("mongodb://localhost/"); database = mongoc_client_get_database (client, "test"); mongoc_database_destroy (database); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>
libmongoc-1.3.1/doc/mongoc_delete_flags_t.page000066400000000000000000000017701264720626300214100ustar00rootroot00000000000000 mongoc_delete_flags_t Flags for deletion operations
Synopsis
Deprecated

These flags are deprecated and should not be used in new code.

Please use mongoc_remove_flags_t with mongoc_collection_remove() instead.

libmongoc-1.3.1/doc/mongoc_find_and_modify_opts_destroy.page000066400000000000000000000021511264720626300243700ustar00rootroot00000000000000 mongoc_find_and_modify_opts_destroy()
Synopsis

New in mongoc 1.3.0

Parameters

find_and_modify_opts

A mongoc_find_and_modify_opts_t.

Description

Frees all resources associated with the find and modify builder structure.

libmongoc-1.3.1/doc/mongoc_find_and_modify_opts_new.page000066400000000000000000000017721264720626300235000ustar00rootroot00000000000000 mongoc_find_and_modify_opts_new()
Synopsis

New in mongoc 1.3.0

Returns

Creates a newly allocated find and modify builder structure that is used to create a findAndModify command. This should be freed with mongoc_find_and_modify_opts_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_find_and_modify_opts_set_bypass_document_validation.page000066400000000000000000000047101264720626300311660ustar00rootroot00000000000000 mongoc_find_and_modify_opts_set_bypass_document_validation()
Synopsis

New in MongoDB 3.2 and mongoc 1.3.0

This option is only available when talking to MongoDB 3.2 and later.

Parameters

opts

A mongoc_find_and_modify_opts_t.

bypass

If the schema validation rules should be ignored.

Description

Adds bypassDocumentValidation argument to the builder.

When authentication is enabled, the authenticated user must have either the "dbadmin" or "restore" roles to bypass document validation.

Returns

Returns true if it successfully added the option to the builder.

Setting bypassDocumentValidation

Outputs:

libmongoc-1.3.1/doc/mongoc_find_and_modify_opts_set_fields.page000066400000000000000000000040161264720626300250220ustar00rootroot00000000000000 mongoc_find_and_modify_opts_set_fields()
Synopsis

New in mongoc 1.3.0

Parameters

opts

A mongoc_find_and_modify_opts_t.

fields

A subset of fields to return. Choose which fields to include by appending {fieldname: 1} for each fieldname, or excluding it with {fieldname: 0}.

Description

Adds fields argument to the builder.

Returns

Returns true if it successfully added the option to the builder.

Setting fields

Outputs:

libmongoc-1.3.1/doc/mongoc_find_and_modify_opts_set_flags.page000066400000000000000000000051771264720626300246610ustar00rootroot00000000000000 mongoc_find_and_modify_opts_set_flags()
Synopsis

New in mongoc 1.3.0

Parameters

opts

A mongoc_find_and_modify_opts_t.

flags

.

Description

Adds one or more flags to the builder.

MONGOC_FIND_AND_MODIFY_NONE

Default. Doesn't add anything to the builder.

MONGOC_FIND_AND_MODIFY_REMOVE

Will instruct find_and_modify to remove the matching document.

MONGOC_FIND_AND_MODIFY_UPSERT

Update the matching document or, if no document matches, insert the document.

MONGOC_FIND_AND_MODIFY_RETURN_NEW

Return the resulting document.

Returns

Returns true if it successfully added the option to the builder.

Setting flags

Outputs:

libmongoc-1.3.1/doc/mongoc_find_and_modify_opts_set_sort.page000066400000000000000000000042671264720626300245530ustar00rootroot00000000000000 mongoc_find_and_modify_opts_set_sort()
Synopsis

New in mongoc 1.3.0

Parameters

opts

A mongoc_find_and_modify_opts_t.

sort

Determines which document the operation modifies if the query selects multiple documents. findAndModify modifies the first document in the sort order specified by this argument.

Description

Adds sort argument to the builder.

Returns

Returns true if it successfully added the option to the builder.

Setting sort

Outputs:

libmongoc-1.3.1/doc/mongoc_find_and_modify_opts_set_update.page000066400000000000000000000042501264720626300250360ustar00rootroot00000000000000 mongoc_find_and_modify_opts_set_update()
Synopsis

New in mongoc 1.3.0

Parameters

opts

A mongoc_find_and_modify_opts_t.

update

The update document is the same format as the update document passed to mongoc_collection_update.

Description

Adds update argument to the builder.

Returns

Returns true if it successfully added the option to the builder.

Setting update

Outputs:

libmongoc-1.3.1/doc/mongoc_find_and_modify_opts_t.page000066400000000000000000000102411264720626300231410ustar00rootroot00000000000000 mongoc_find_and_modify_opts_t find_and_modify abstraction
Synopsis

mongoc_find_and_modify_opts_t is a builder interface to construct a find_and_modify command.

It was created to be able to accommodate new arguments to the MongoDB find_and_modify command.

New in mongoc 1.3.0

As of MongoDB 3.2, the mongoc_write_concern_t specified on the mongoc_collection_t will be used, if any.

Example <file>find-and-modify-with-opts.c</file>

Outputs:

Functions
libmongoc-1.3.1/doc/mongoc_get_major_version.page000066400000000000000000000013321264720626300221550ustar00rootroot00000000000000 mongoc_get_major_version()
Synopsis
Returns

The value of MONGOC_MAJOR_VERSION when libmongoc was compiled.

libmongoc-1.3.1/doc/mongoc_get_micro_version.page000066400000000000000000000013321264720626300221560ustar00rootroot00000000000000 mongoc_get_micro_version()
Synopsis
Returns

The value of MONGOC_MICRO_VERSION when libmongoc was compiled.

libmongoc-1.3.1/doc/mongoc_get_minor_version.page000066400000000000000000000013321264720626300221710ustar00rootroot00000000000000 mongoc_get_minor_version()
Synopsis
Returns

The value of MONGOC_MINOR_VERSION when libmongoc was compiled.

libmongoc-1.3.1/doc/mongoc_get_version.page000066400000000000000000000013461264720626300207720ustar00rootroot00000000000000 mongoc_get_version()
Synopsis
Returns

A string representation of libmongoc's version, formatted something like "1.2.3" or "1.2.3-dev".

libmongoc-1.3.1/doc/mongoc_gridfs_create_file.page000066400000000000000000000030761264720626300222500ustar00rootroot00000000000000 mongoc_gridfs_create_file()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t.

opt

A mongoc_gridfs_file_opt_t to specify file options.

Description

This function shall create a new mongoc_gridfs_file_t.

Use mongoc_gridfs_file_writev() to write to the file.

Returns

Returns a newly allocated mongoc_gridfs_file_t that should be freed with mongoc_gridfs_file_destroy().

libmongoc-1.3.1/doc/mongoc_gridfs_create_file_from_stream.page000066400000000000000000000035671264720626300246530ustar00rootroot00000000000000 mongoc_gridfs_create_file_from_stream()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t().

stream

A mongoc_stream_t.

opt

A mongoc_gridfs_file_opt_t to specify file options.

Description

This function shall create a new mongoc_gridfs_file_t and fill it with the contents of stream. Note that this function will read from stream until End of File, making it bet suited for file-backed streams.

Returns

A newly allocated mongoc_gridfs_file_t that should be freed with mongoc_gridfs_file_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_gridfs_destroy.page000066400000000000000000000017621264720626300214770ustar00rootroot00000000000000 mongoc_gridfs_destroy()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t.

Description

This function shall destroy the gridfs structure referenced by gridfs and any resources associated with the gridfs.

libmongoc-1.3.1/doc/mongoc_gridfs_drop.page000066400000000000000000000026171264720626300207520ustar00rootroot00000000000000 mongoc_gridfs_drop()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t.

error

An optional location for a bson_error_t or NULL.

Description

Requests that an entire GridFS be dropped, including all files associated with it.

Errors

Errors are propagated via the error parameter.

Returns

Returns true if successful, otherwise false and error is set.

libmongoc-1.3.1/doc/mongoc_gridfs_file_destroy.page000066400000000000000000000020121264720626300224630ustar00rootroot00000000000000 mongoc_gridfs_file_destroy()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Destroys the mongoc_gridfs_file_t instance and any resources associated with it.

libmongoc-1.3.1/doc/mongoc_gridfs_file_error.page000066400000000000000000000027631264720626300221400ustar00rootroot00000000000000 mongoc_gridfs_file_error()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

error

An optional location for a bson_error_t or NULL.

Description

This function checks to see if there has been an error associated with the last operation upon file.

Errors

Errors are propagated via the error parameter.

Returns

Returns false if there has been no registered error, otherwise true and error is set.

libmongoc-1.3.1/doc/mongoc_gridfs_file_get_aliases.page000066400000000000000000000022021264720626300232530ustar00rootroot00000000000000 mongoc_gridfs_file_get_aliases()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Fetches the aliases associated with a gridfs file.

Returns

Returns a const bson_t * that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_gridfs_file_get_chunk_size.page000066400000000000000000000021121264720626300237740ustar00rootroot00000000000000 mongoc_gridfs_file_get_chunk_size()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Fetches the chunk size used with the underlying gridfs file.

Returns

A signed 32-bit integer.

libmongoc-1.3.1/doc/mongoc_gridfs_file_get_content_type.page000066400000000000000000000021611264720626300243510ustar00rootroot00000000000000 mongoc_gridfs_file_get_content_type()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Fetches the content type specified for the underlying file.

Returns

Returns a string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_gridfs_file_get_filename.page000066400000000000000000000021221264720626300234130ustar00rootroot00000000000000 mongoc_gridfs_file_get_filename()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Fetches the filename for the given gridfs file.

Returns

A string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_gridfs_file_get_id.page000066400000000000000000000024041264720626300222320ustar00rootroot00000000000000 mongoc_gridfs_file_get_id()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Fetches the id of a gridfs file.

The C Driver always uses an ObjectId for _id, but files created by other drivers may have any type of _id.

Returns

Returns a const bson_value_t * that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_gridfs_file_get_length.page000066400000000000000000000020601264720626300231150ustar00rootroot00000000000000 mongoc_gridfs_file_get_length()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Fetches the length of the gridfs file in bytes.

Returns

A 64-bit signed integer.

libmongoc-1.3.1/doc/mongoc_gridfs_file_get_md5.page000066400000000000000000000021301264720626300223170ustar00rootroot00000000000000 mongoc_gridfs_file_get_md5()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Fetches the pre-computed MD5 for the underlying gridfs file.

Returns

Returns a string that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_gridfs_file_get_metadata.page000066400000000000000000000022301264720626300234130ustar00rootroot00000000000000 mongoc_gridfs_file_get_metadata()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Fetches a bson document containing the metadata for the gridfs file.

Returns

Returns a const bson_t * that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_gridfs_file_get_upload_date.page000066400000000000000000000022331264720626300241170ustar00rootroot00000000000000 mongoc_gridfs_file_get_upload_date()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Fetches the specified upload date of the gridfs file in milliseconds since the UNIX epoch.

Returns

A signed int64 with the upload date in milliseconds since the UNIX epoch.

libmongoc-1.3.1/doc/mongoc_gridfs_file_list_destroy.page000066400000000000000000000020101264720626300235140ustar00rootroot00000000000000 mongoc_gridfs_file_list_destroy()
Synopsis
Parameters

list

A mongoc_gridfs_file_list_t.

Description

Frees a mongoc_gridfs_file_list_t and releases any associated resources.

libmongoc-1.3.1/doc/mongoc_gridfs_file_list_error.page000066400000000000000000000027541264720626300231730ustar00rootroot00000000000000 mongoc_gridfs_file_list_error()
Synopsis
Parameters

list

A mongoc_gridfs_file_list_t.

error

An optional location for a bson_error_t or NULL.

Description

Fetches any error that has occurred while trying to retrieve the file list.

Errors

Errors are propagated via the error parameter.

Returns

false if no error has been registered, otherwise true and error is set.

libmongoc-1.3.1/doc/mongoc_gridfs_file_list_next.page000066400000000000000000000025261264720626300230150ustar00rootroot00000000000000 mongoc_gridfs_file_list_next()
Synopsis
Parameters

list

A mongoc_gridfs_file_list_t.

Description

This function shall iterate the underlying gridfs file list, returning the next file each iteration. This is a blocking function.

Returns

A newly allocated mongoc_gridfs_file_t that should be freed with mongoc_gridfs_file_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_gridfs_file_list_t.page000066400000000000000000000027521264720626300223030ustar00rootroot00000000000000 mongoc_gridfs_file_list_t
Synopsis typedef struct _mongoc_gridfs_file_list_t mongoc_gridfs_file_list_t;]]>
Description

mongoc_gridfs_file_list_t provides a gridfs file list abstraction. It provides iteration and basic marshalling on top of a regular mongoc_collection_find() style query. In interface, it's styled after mongoc_cursor_t.

Example
Functions
libmongoc-1.3.1/doc/mongoc_gridfs_file_opt_t.page000066400000000000000000000021101264720626300221160ustar00rootroot00000000000000 mongoc_gridfs_file_opt_t
Synopsis
Description

This structure contains options that can be set on a mongoc_gridfs_file_t. It can be used by various functions when creating a new gridfs file.

Functions
libmongoc-1.3.1/doc/mongoc_gridfs_file_readv.page000066400000000000000000000037661264720626300221140ustar00rootroot00000000000000 mongoc_gridfs_file_readv()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

iov

An array of mongoc_iovec_t.

iovcnt

The number of elements in iov.

min_bytes

The minimum number of bytes that must be read or an error will be synthesized.

timeout_msec

A uint32_t with the timeout in milliseconds.

Description

This function performs a scattered read from file, potentially blocking to read from the MongoDB server.

Timeout should be the number of milliseconds to allow blocking, or 0 to disallow blocking.

Returns

Returns the number of bytes read, or -1 on failure. Use mongoc_gridfs_file_error to retrieve error details.

libmongoc-1.3.1/doc/mongoc_gridfs_file_remove.page000066400000000000000000000026421264720626300223000ustar00rootroot00000000000000 mongoc_gridfs_file_remove()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

error

An optional location for a bson_error_t or NULL.

Description

Removes file and its data chunks from the MongoDB server.

Returns

Returns true if successful, otherwise false and error is set.

Errors

Errors are propagated via the error parameter.

libmongoc-1.3.1/doc/mongoc_gridfs_file_save.page000066400000000000000000000023401264720626300217340ustar00rootroot00000000000000 mongoc_gridfs_file_save()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

Saves modifications to file to the MongoDB server.

If an error occurred, false is returned and the error can be retrieved with mongoc_gridfs_file_error().

Returns

Returns true if successful, otherwise false.

libmongoc-1.3.1/doc/mongoc_gridfs_file_seek.page000066400000000000000000000046301264720626300217310ustar00rootroot00000000000000 mongoc_gridfs_file_seek()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

delta

The amount to move the file position. May be positive or negative.

whence

One of SEEK_SET, SEEK_CUR or SEEK_END.

Description

Adjust the file position pointer in the given file by delta, starting from the position whence. The whence argument is interpreted as in fseek(2):

SEEK_SET

Set the position relative to the start of the file.

SEEK_CUR

Move delta relative to the current file position.

SEEK_END

Move delta relative to the end of the file.

On success, the file's underlying position pointer is set appropriately. On failure, the file position is NOT changed and errno is set to indicate the error.

Errors

EINVAL

whence is not one of SEEK_SET, SEEK_CUR or SEEK_END.

EINVAL

The resulting file position would be negative.

Returns

Returns 0 if successful; otherwise -1 and errno is set.

libmongoc-1.3.1/doc/mongoc_gridfs_file_set_aliases.page000066400000000000000000000023511264720626300232740ustar00rootroot00000000000000 mongoc_gridfs_file_set_aliases()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

bson

A bson_t containing the aliases.

Description

Sets the aliases for a gridfs file.

You need to call mongoc_gridfs_file_save() to persist this change.

libmongoc-1.3.1/doc/mongoc_gridfs_file_set_content_type.page000066400000000000000000000024511264720626300243670ustar00rootroot00000000000000 mongoc_gridfs_file_set_content_type()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

str

A string containing the content type.

Description

Sets the content type for the gridfs file. This should be something like "text/plain".

You need to call mongoc_gridfs_file_save() to persist this change.

libmongoc-1.3.1/doc/mongoc_gridfs_file_set_filename.page000066400000000000000000000023441264720626300234350ustar00rootroot00000000000000 mongoc_gridfs_file_set_filename()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

str

A UTF-8 encoded string containing the filename.

Description

Sets the filename for file.

You need to call mongoc_gridfs_file_save() to persist this change.

libmongoc-1.3.1/doc/mongoc_gridfs_file_set_md5.page000066400000000000000000000023101264720626300223330ustar00rootroot00000000000000 mongoc_gridfs_file_set_md5()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

str

A string containing the MD5 of the file.

Description

Sets the MD5 checksum for file.

You need to call mongoc_gridfs_file_save() to persist this change.

libmongoc-1.3.1/doc/mongoc_gridfs_file_set_metadata.page000066400000000000000000000024251264720626300234350ustar00rootroot00000000000000 mongoc_gridfs_file_set_metadata()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

bson

A bson_t containing metadata for file.

Description

Sets the metadata associated with file.

You need to call mongoc_gridfs_file_save() to persist this change.

libmongoc-1.3.1/doc/mongoc_gridfs_file_t.page000066400000000000000000000033131264720626300212420ustar00rootroot00000000000000 mongoc_gridfs_file_t
Synopsis
Description

This structure provides a MongoDB GridFS file abstraction. It provides several APIs.

readv, writev, seek, and tell.

General file metadata such as filename and length.

GridFS metadata such as md5, filename, content_type, aliases, metadata, chunk_size, and upload_date.

Thread Safety

This structure is NOT thread-safe and should only be used from one thread at a time.

Functions
libmongoc-1.3.1/doc/mongoc_gridfs_file_tell.page000066400000000000000000000021351264720626300217400ustar00rootroot00000000000000 mongoc_gridfs_file_tell()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

Description

This function returns the current position indicator within file.

Returns

Returns a file position as an unsigned 64-bit integer.

libmongoc-1.3.1/doc/mongoc_gridfs_file_writev.page000066400000000000000000000032311264720626300223160ustar00rootroot00000000000000 mongoc_gridfs_file_writev()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

iov

An array of mongoc_iovec_t.

iovcnt

The number of elements in iov.

timeout_msec

A uint32_t with the timeout in milliseconds.

Description

Performs a gathered write to the underlying gridfs file.

If timeout is reached, then -1 is returned and errno is set to ETIMEDOUT.

Returns

Returns the number of bytes written or -1 upon error and errno is set.

libmongoc-1.3.1/doc/mongoc_gridfs_find.page000066400000000000000000000026611264720626300207250ustar00rootroot00000000000000 mongoc_gridfs_find()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t.

query

A bson_t.

Description

Finds all gridfs files matching query. You can iterate the matched gridfs files with the resulting file list.

Returns

A newly allcoated mongoc_gridfs_file_list_t that should be freed with mongoc_gridfs_file_list_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_gridfs_find_one.page000066400000000000000000000034671264720626300215730ustar00rootroot00000000000000 mongoc_gridfs_find_one()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t.

query

A bson_t.

error

An optional location for a bson_error_t or NULL.

Description

This function shall execute a query on the underlying gridfs implementation. The first file matching query will be returned.

Errors

Errors are propagated via the error parameter.

Returns

A newly allcoated mongoc_gridfs_file_t or NULL if no file could be found. You must free the resulting file with mongoc_gridfs_file_destroy() if non-NULL.

libmongoc-1.3.1/doc/mongoc_gridfs_find_one_by_filename.page000066400000000000000000000036251264720626300241210ustar00rootroot00000000000000 mongoc_gridfs_find_one_by_filename()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t.

filename

A UTF-8 encoded string containing the filename.

error

An optional location for a bson_error_t or NULL.

Description

Finds the first file matching the filename specified. If no file could be found, NULL is returned and error is set.

Errors

Errors are propagated via the error parameter.

Returns

Returns a newly allocated mongoc_gridfs_file_t if successful, otherwise NULL and error is set. You must free the resulting file with mongoc_gridfs_file_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_gridfs_get_chunks.page000066400000000000000000000024551264720626300221400ustar00rootroot00000000000000 mongoc_gridfs_get_chunks()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t.

Description

Returns a mongoc_collection_t that contains the chunks for files. This instance is owned by the mongoc_gridfs_t instance and should not be modified or freed.

Returns

Returns a mongoc_collection_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_gridfs_get_files.page000066400000000000000000000024511264720626300217430ustar00rootroot00000000000000 mongoc_gridfs_get_files()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t.

Description

Retrieves the mongoc_collection_t containing the file metadata for GridFS. This instance is owned by the mongoc_gridfs_t and should not be modified or freed.

Returns

Returns a mongoc_collection_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_gridfs_remove_by_filename.page000066400000000000000000000032451264720626300236330ustar00rootroot00000000000000 mongoc_gridfs_remove_by_filename()
Synopsis
Parameters

gridfs

A mongoc_gridfs_t.

filename

A UTF-8 encoded string containing the filename.

error

An optional location for a bson_error_t or NULL.

Description

Removes all files matching filename and their data chunks from the MongoDB server.

Returns

Returns true if successful (including when no files match), otherwise false and error is set.

Errors

Errors are propagated via the error parameter.

libmongoc-1.3.1/doc/mongoc_gridfs_t.page000066400000000000000000000051351264720626300202470ustar00rootroot00000000000000 mongoc_gridfs_t
Synopsis typedef struct _mongoc_gridfs_t mongoc_gridfs_t;]]>
Description

mongoc_gridfs_t provides a MongoDB gridfs implementation. The system as a whole is made up of gridfs objects, which contain gridfs_files and gridfs_file_lists. Essentially, a basic file system API.

There are extensive caveats about the kind of use cases gridfs is practical for. In particular, any writing after initial file creation is likely to both break any concurrent readers and be quite expensive. That said, this implementation does allow for arbitrary writes to existing gridfs object, just use them with caution.

mongoc_gridfs also integrates tightly with the mongoc_stream_t abstraction, which provides some convenient wrapping for file creation and reading/writing. It can be used without, but its worth looking to see if your problem can fit that model.

mongoc_gridfs_t does not support read preferences. In a replica set, GridFS queries are always routed to the primary.

Thread Safety

mongoc_gridfs_t is NOT thread-safe and should only be used in the same thread as the owning mongoc_client_t.

Lifecycle

It is an error to free a mongoc_gridfs_t before freeing all related instances of mongoc_gridfs_file_t and mongoc_gridfs_file_list_t.

Example <file>example-gridfs.c</file>
Functions
libmongoc-1.3.1/doc/mongoc_host_list_t.page000066400000000000000000000024021264720626300207730ustar00rootroot00000000000000 mongoc_host_list_t
Synopsis
Description

The host and port of a MongoDB server. Can be part of a linked list: for example the return value of mongoc_uri_get_hosts when multiple hosts are provided in the MongoDB URI.

See Also

mongoc_uri_get_hosts and mongoc_cursor_get_host.

libmongoc-1.3.1/doc/mongoc_index_opt_geo_get_default.page000066400000000000000000000014341264720626300236320ustar00rootroot00000000000000 mongoc_index_opt_geo_get_default()
Synopsis
Returns

Returns a pointer to the default GEO index creation options.

libmongoc-1.3.1/doc/mongoc_index_opt_geo_init.page000066400000000000000000000020371264720626300223120ustar00rootroot00000000000000 mongoc_index_opt_geo_init()
Synopsis
Parameters

opt

A mongoc_index_opt_geo_t.

Description

This function will initialize opt to the default values. It should be called before modifying any fields within the structure.

libmongoc-1.3.1/doc/mongoc_index_opt_geo_t.page000066400000000000000000000024141264720626300216110ustar00rootroot00000000000000 mongoc_index_opt_geo_t
Synopsis typedef struct { uint8_t twod_sphere_version; uint8_t twod_bits_precision; double twod_location_min; double twod_location_max; double haystack_bucket_size; uint8_t *padding[32]; } mongoc_index_opt_geo_t;]]>
Description

This structure contains the options that may be used for tuning a GEO index.

Functions
See Also

mongoc_index_opt_t

mongoc_index_opt_wt_t

libmongoc-1.3.1/doc/mongoc_index_opt_get_default.page000066400000000000000000000014041264720626300227750ustar00rootroot00000000000000 mongoc_index_opt_get_default()
Synopsis
Returns

Returns a pointer to the default index creation options.

libmongoc-1.3.1/doc/mongoc_index_opt_init.page000066400000000000000000000020031264720626300214510ustar00rootroot00000000000000 mongoc_index_opt_init()
Synopsis
Parameters

opt

A mongoc_index_opt_t.

Description

This function will initialize opt to the default values. It should be called before modifying any fields within the structure.

libmongoc-1.3.1/doc/mongoc_index_opt_t.page000066400000000000000000000056501264720626300207640ustar00rootroot00000000000000 mongoc_index_opt_t
Synopsis typedef struct { bool is_initialized; bool background; bool unique; const char *name; bool drop_dups; bool sparse; int32_t expire_after_seconds; int32_t v; const bson_t *weights; const char *default_language; const char *language_override; mongoc_index_opt_geo_t *geo_options; mongoc_index_opt_storage_t *storage_options; const bson_t *partial_filter_expression; void *padding[5]; } mongoc_index_opt_t;]]>
Description

This structure contains the options that may be used for tuning a specific index.

See the createIndexes documentations in the MongoDB manual for descriptions of individual options.

NOTE: dropDups is deprecated as of MongoDB version 3.0.0. This option is silently ignored by the server and unique index builds using this option will fail if a duplicate value is detected.

Example
Functions
See Also

mongoc_index_opt_geo_t

mongoc_index_opt_wt_t

libmongoc-1.3.1/doc/mongoc_index_opt_wt_get_default.page000066400000000000000000000014361264720626300235140ustar00rootroot00000000000000 mongoc_index_opt_wt_get_default()
Synopsis
Returns

Returns a pointer to the default WiredTiger index creation options.

libmongoc-1.3.1/doc/mongoc_index_opt_wt_init.page000066400000000000000000000020301264720626300221630ustar00rootroot00000000000000 mongoc_index_opt_wt_init()
Synopsis
Parameters

opt

A mongoc_index_opt_wt_t.

Description

This function will initialize opt to the default values. It should be called before modifying any fields within the structure.

libmongoc-1.3.1/doc/mongoc_index_opt_wt_t.page000066400000000000000000000023361264720626300214740ustar00rootroot00000000000000 mongoc_index_opt_wt_t
Synopsis typedef struct { mongoc_index_opt_storage_t base; const char *config_str; void *padding[8]; } mongoc_index_opt_wt_t;]]>
Description

This structure contains the options that may be used for tuning a WiredTiger specific index.

Functions
See Also

mongoc_index_opt_t

mongoc_index_opt_wt_t

libmongoc-1.3.1/doc/mongoc_init.page000066400000000000000000000016361264720626300174130ustar00rootroot00000000000000 mongoc_init()
Synopsis
Description

This function should be called at the beginning of every program using the MongoDB C driver. It is responsible for initializing global state such as process counters, SSL, and threading primatives.

When your process has completed, you should also call mongoc_cleanup.

libmongoc-1.3.1/doc/mongoc_insert_flags_t.page000066400000000000000000000031141264720626300214440ustar00rootroot00000000000000 mongoc_insert_flags_t Flags for deletion operations
Synopsis
Description

These flags correspond to the MongoDB wire protocol. They may be bitwise or'd together. They may modify how an insert happens on the MongoDB server.

Flag Values

MONGOC_INSERT_NONE

Specify no insert flags.

MONGOC_INSERT_CONTINUE_ON_ERROR

Continue inserting documents from the insertion set even if one insert fails.

MONGOC_INSERT_NO_VALIDATE

Do not validate insertion documents before performing an insert. Validation can be expensive, so this can save some time if you know your documents are already valid.

libmongoc-1.3.1/doc/mongoc_iovec_t.page000066400000000000000000000023301264720626300200700ustar00rootroot00000000000000 mongoc_iovec_t
Synopsis
Synopsis #ifdef _WIN32 typedef struct { u_long iov_len; char *iov_base; } mongoc_iovec_t; #else typedef struct iovec mongoc_iovec_t; #endif ]]>

The mongoc_iovec_t structure is a portability abstraction for consumers of the mongoc_stream_t interfaces. It allows for scatter/gather I/O through the socket subsystem.

When writing portable code, beware of the ordering of iov_len and iov_base as they are different on various platforms. Therefore, you should not use C initializers for initialization.

libmongoc-1.3.1/doc/mongoc_matcher_destroy.page000066400000000000000000000021201264720626300216310ustar00rootroot00000000000000 mongoc_matcher_destroy()
Synopsis

Release all resources associated with matcher including freeing the structure.

Deprecated

mongoc_matcher_t is deprecated and will be removed in version 2.0.

Parameters

matcher

A mongoc_matcher_t.

libmongoc-1.3.1/doc/mongoc_matcher_match.page000066400000000000000000000030151264720626300212400ustar00rootroot00000000000000 mongoc_matcher_match()
Synopsis

This function will check to see if the query compiled in matcher matches document.

Deprecated

mongoc_matcher_t is deprecated and will be removed in version 2.0.

Parameters

matcher

A mongoc_matcher_t.

query

A bson_t that contains the query.

Returns

true if document matches the query specification provided to mongoc_matcher_new(). Otherwise, false.

libmongoc-1.3.1/doc/mongoc_matcher_new.page000066400000000000000000000034661264720626300207470ustar00rootroot00000000000000 mongoc_matcher_new()
Synopsis

Create a new mongoc_matcher_t using the query specification provided.

Deprecated

mongoc_matcher_t is deprecated and will be removed in version 2.0.

Parameters

query

A bson_t.

error

An optional location for a bson_error_t or NULL.

Errors

Errors are propagated via the error parameter.

Returns

A newly allocated mongoc_matcher_t that should be freed with mongoc_matcher_destroy() when no longer in use. Upon failure, NULL is returned and error is set. This could happen if query contains an invalid query specification.

libmongoc-1.3.1/doc/mongoc_matcher_t.page000066400000000000000000000044321264720626300204130ustar00rootroot00000000000000 mongoc_matcher_t Client-side document matching abstraction
Synopsis

mongoc_matcher_t provides a reduced-interface for client-side matching of BSON documents.

It can perform the basics such as $in, $nin, $eq, $neq, $gt, $gte, $lt, and $lte.

mongoc_matcher_t does not currently support the full spectrum of query operations that the MongoDB server supports.

Deprecated

mongoc_matcher_t is deprecated and will be removed in version 2.0.

Functions
Example Filter a sequence of BSON documents from STDIN based on a query. #include #include #include int main (int argc, char *argv[]) { mongoc_matcher_t *matcher; bson_reader_t *reader; const bson_t *bson; bson_t *spec; char *str; int fd; mongoc_init (); #ifdef _WIN32 fd = fileno (stdin); #else fd = STDIN_FILENO; #endif reader = bson_reader_new_from_fd (fd, false); spec = BCON_NEW ("hello", "world"); matcher = mongoc_matcher_new (spec, NULL); while ((bson = bson_reader_read (reader, NULL))) { if (mongoc_matcher_match (matcher, bson)) { str = bson_as_json (bson, NULL); printf ("%s\n", str); bson_free (str); } } bson_reader_destroy (reader); bson_destroy (spec); mongoc_cleanup (); return 0; }]]>
libmongoc-1.3.1/doc/mongoc_query_flags_t.page000066400000000000000000000051431264720626300213110ustar00rootroot00000000000000 mongoc_query_flags_t Flags for deletion operations
Synopsis
Description

These flags correspond to the MongoDB wire protocol. They may be bitwise or'd together. They may modify how a query is performed in the MongoDB server.

Flag Values

MONGOC_QUERY_NONE

Specify no query flags.

MONGOC_QUERY_TAILABLE_CURSOR

Cursor will not be closed when the last data is retrieved. You can resume this cursor later.

MONGOC_QUERY_SLAVE_OK

Allow query of replica set secondaries.

MONGOC_QUERY_OPLOG_REPLAY

Used internally by MongoDB.

MONGOC_QUERY_NO_CURSOR_TIMEOUT

The server normally times out an idle cursor after an inactivity period (10 minutes). This prevents that.

MONGOC_QUERY_AWAIT_DATA

Use with MONGOC_QUERY_TAILABLE_CURSOR. Block rather than returning no data. After a period, time out.

MONGOC_QUERY_EXHAUST

Stream the data down full blast in multiple "reply" packets. Faster when you are pulling down a lot of data and you know you want to retrieve it all.

MONGOC_QUERY_PARTIAL

Get partial results from mongos if some shards are down (instead of throwing an error).

libmongoc-1.3.1/doc/mongoc_rand.page000066400000000000000000000041221264720626300173650ustar00rootroot00000000000000 mongoc_rand MongoDB Random Number Generator
Synopsis
Description

The mongoc_rand family of functions provide access to the low level randomness primitives used by the MongoDB C Driver. In particular, they control the creation of cryptographically strong pseudo-random bytes required by some security mechanisms.

While we can usually pull enough entropy from the environment, you may be required to seed the PRNG manually depending on your OS, hardware and other entropy consumers running on the same system.

Entropy

mongoc_rand_add and mongoc_rand_seed allow the user to directly provide entropy. They differ insofar as mongoc_rand_seed requires that each bit provided is fully random. mongoc_rand_add allows the user to specify the degree of randomness in the provided bytes as well.

Status

The mongoc_rand_status function allows the user to check the status of the mongoc PRNG. This can be used to guarantee sufficient entropy at program startup, rather than waiting for runtime errors to occur.

Functions
libmongoc-1.3.1/doc/mongoc_rand_add.page000066400000000000000000000022541264720626300202010ustar00rootroot00000000000000 mongoc_rand_add()
Synopsis
Description

Mixes num bytes of data into the mongoc random number generator. Entropy specifies a lower bound estimate of the randomness contained in buf.

Parameters

buf

A buffer.

num

An int of number of bytes in buf.

entropy

A double of randomness estimate in buf.

libmongoc-1.3.1/doc/mongoc_rand_seed.page000066400000000000000000000017421264720626300203720ustar00rootroot00000000000000 mongoc_rand_seed()
Synopsis
Description

Seeds the mongoc random number generator with num bytes of entropy.

Parameters

buf

A buffer.

num

An int of number of bytes in buf.

libmongoc-1.3.1/doc/mongoc_rand_status.page000066400000000000000000000015101264720626300207660ustar00rootroot00000000000000 mongoc_rand_status()
Synopsis
Description

The status of the mongoc random number generator.

Returns

Returns 1 if the PRNG has been seeded with enough data, 0 otherwise.

libmongoc-1.3.1/doc/mongoc_read_concern_copy.page000066400000000000000000000023601264720626300221170ustar00rootroot00000000000000 mongoc_read_concern_copy()
Synopsis
Parameters

read_concern

A mongoc_read_concern_t.

Description

Performs a deep copy of read_concern.

Returns

Returns a newly allocated copy of read_concern that should be freed with mongoc_read_concern_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_read_concern_destroy.page000066400000000000000000000017461264720626300226450ustar00rootroot00000000000000 mongoc_read_concern_destroy()
Synopsis
Parameters

read_concern

A mongoc_read_concern_t.

Description

Frees all resources associated with the read concern structure.

libmongoc-1.3.1/doc/mongoc_read_concern_get_level.page000066400000000000000000000021641264720626300231150ustar00rootroot00000000000000 mongoc_read_concern_get_level()
Synopsis
Parameters

read_concern

A mongoc_read_concern_t.

Description

Returns the currently set read concern.

Returns

Returns the current readConcern. If none is set, returns empty string.

libmongoc-1.3.1/doc/mongoc_read_concern_new.page000066400000000000000000000015761264720626300217460ustar00rootroot00000000000000 mongoc_read_concern_new()
Synopsis
Returns

Creates a newly allocated read concern that can be configured based on user preference. This should be freed with mongoc_read_concern_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_read_concern_set_level.page000066400000000000000000000023521264720626300231300ustar00rootroot00000000000000 mongoc_read_concern_set_level()
Synopsis
Parameters

read_concern

A mongoc_read_concern_t.

level

The readConcern level to use. Should be either MONGOC_READ_CONCERN_LEVEL_LOCAL or MONGOC_READ_CONCERN_LEVEL_MAJORITY.

Description

The readConcern option allows clients to choose a level of isolation for their reads.

libmongoc-1.3.1/doc/mongoc_read_concern_t.page000066400000000000000000000036241264720626300214140ustar00rootroot00000000000000 mongoc_read_concern_t Read Concern abstraction
Synopsis

New in MongoDB 3.2 and mongoc 1.3.0

The mongoc_read_concern_t allows clients to choose a level of isolation for their reads. The default, MONGOC_READ_CONCERN_LEVEL_LOCAL, is right for the great majority of applications.

You can specify a read concern on connection objects, database objects, or collection objects.

See readConcern on the MongoDB website for more information.

Read Concern is only sent to MongoDB when it has explicitly been set by mongoc_read_concern_set_level to anything other then empty string.

Read Concern Levels

MONGOC_READ_CONCERN_LEVEL_LOCAL ("local")

Default. The query will return the node’s most recent copy of data. Provides no guarantee that the data has been written to a majority of the nodes.

MONGOC_READ_CONCERN_LEVEL_MAJORITY ("majority")

The query will return the node’s most recent copy of the data confirmed as having been written to a majority of the nodes.

Functions
libmongoc-1.3.1/doc/mongoc_read_mode_t.page000066400000000000000000000022631264720626300207070ustar00rootroot00000000000000 mongoc_read_mode_t Read Preference Modes
Synopsis
Description

This enum describes how reads should be dispatched. The default is MONGOC_READ_PRIMARY.

Please see the MongoDB website for a description of Read Preferences.

libmongoc-1.3.1/doc/mongoc_read_prefs_add_tag.page000066400000000000000000000021311264720626300222140ustar00rootroot00000000000000 mongoc_read_prefs_add_tag()
Synopsis
Parameters

read_prefs

A mongoc_read_prefs_t.

tag

A bson_t.

Description

This function shall add a tag to a read preference.

libmongoc-1.3.1/doc/mongoc_read_prefs_copy.page000066400000000000000000000022611264720626300216070ustar00rootroot00000000000000 mongoc_read_prefs_copy()
Synopsis
Parameters

read_prefs

A mongoc_read_prefs_t.

Description

This function shall deep copy a read preference.

Returns

Returns a newly allocated read preference that should be freed with mongoc_read_prefs_destroy().

libmongoc-1.3.1/doc/mongoc_read_prefs_destroy.page000066400000000000000000000017141264720626300223300ustar00rootroot00000000000000 mongoc_read_prefs_destroy()
Synopsis
Parameters

read_prefs

A mongoc_read_prefs_t.

Description

Frees a read preference and all associated resources.

libmongoc-1.3.1/doc/mongoc_read_prefs_get_mode.page000066400000000000000000000021711264720626300224200ustar00rootroot00000000000000 mongoc_read_prefs_get_mode()
Synopsis
Parameters

read_prefs

A mongoc_read_prefs_t.

Description

Fetches the mongoc_read_mode_t for the read preference.

Returns

Returns the read preference mode.

libmongoc-1.3.1/doc/mongoc_read_prefs_get_tags.page000066400000000000000000000022071264720626300224320ustar00rootroot00000000000000 mongoc_read_prefs_get_tags()
Synopsis
Parameters

read_prefs

A mongoc_read_prefs_t.

Description

Fetches any read preference tags that have been registered.

Returns

Returns a bson_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_read_prefs_is_valid.page000066400000000000000000000022611264720626300224270ustar00rootroot00000000000000 mongoc_read_prefs_is_valid()
Synopsis
Parameters

read_prefs

A mongoc_read_prefs_t.

Description

Performs a consistency check of read_prefs to ensure it makes sense and can be satisfied.

This only performs local consistency checks.

Returns

Returns true if the read pref is valid.

libmongoc-1.3.1/doc/mongoc_read_prefs_new.page000066400000000000000000000023771264720626300214360ustar00rootroot00000000000000 mongoc_read_prefs_new()
Synopsis
Parameters

read_mode

A mongoc_read_mode_t.

Description

Creates a new mongoc_read_prefs_t using the mode specified.

Returns

Returns a newly allocated mongoc_read_prefs_t that should be freed with mongoc_read_prefs_destroy().

libmongoc-1.3.1/doc/mongoc_read_prefs_set_mode.page000066400000000000000000000023511264720626300224340ustar00rootroot00000000000000 mongoc_read_prefs_set_mode()
Synopsis
Parameters

read_prefs

A mongoc_read_prefs_t.

mode

A mongoc_read_mode_t.

Description

Sets the read preference mode. See the MongoDB website for more information on Read Preferences.

libmongoc-1.3.1/doc/mongoc_read_prefs_set_tags.page000066400000000000000000000022621264720626300224470ustar00rootroot00000000000000 mongoc_read_prefs_set_tags()
Synopsis
Parameters

read_prefs

A mongoc_read_prefs_t.

tags

A bson_t.

Description

Sets the tags to be used for the read preference. Only mongod instances matching these tags will be suitable for handling the request.

libmongoc-1.3.1/doc/mongoc_read_prefs_t.page000066400000000000000000000067321264720626300211070ustar00rootroot00000000000000 mongoc_read_prefs_t A read preference abstraction
Synopsis

mongoc_read_prefs_t provides an abstraction on top of the MongoDB connection read prefences. It allows for hinting to the driver which nodes in a replica set should be accessed first.

You can specify a read preference mode on connection objects, database objects, collection objects, or per-operation. Generally, it makes the most sense to stick with the global default, MONGOC_READ_PRIMARY. All of the other modes come with caveats that won't be covered in great detail here.

Read Modes

MONGOC_READ_PRIMARY

Default mode. All operations read from the current replica set primary.

MONGOC_READ_SECONDARY

All operations read from among the nearest secondary members of the replica set.

MONGOC_READ_PRIMARY_PREFERRED

In most situations, operations read from the primary but if it is unavailable, operations read from secondary members.

MONGOC_READ_SECONDARY_PREFERRED

In most situations, operations read from among the nearest secondary members, but if no secondaries are available, operations read from the primary.

MONGOC_READ_NEAREST

Operations read from among the nearest members of the replica set, irrespective of the member’s type.

Tag Sets

Tag sets allow you to specify custom read preferences and write concerns so that your application can target operations to specific members.

Custom read preferences and write concerns evaluate tags sets in different ways: read preferences consider the value of a tag when selecting a member to read from. while write concerns ignore the value of a tag to when selecting a member except to consider whether or not the value is unique.

You can specify tag sets with the following read preference modes:

primaryPreferred

secondary

secondaryPreferred

nearest

Tags are not compatible with MONGOC_READ_PRIMARY and, in general, only apply when selecting a secondary member of a set for a read operation. However, the nearest read mode, when combined with a tag set will select the nearest member that matches the specified tag set, which may be a primary or secondary.

All interfaces use the same member selection logic to choose the member to which to direct read operations, basing the choice on read preference mode and tag sets.

Functions
libmongoc-1.3.1/doc/mongoc_remove_flags_t.page000066400000000000000000000024651264720626300214450ustar00rootroot00000000000000 mongoc_remove_flags_t Flags for deletion operations
Synopsis
Description

These flags correspond to the MongoDB wire protocol. They may be bitwise or'd together. They may change the number of documents that are removed during a remove command.

Flag Values

MONGOC_REMOVE_NONE

Specify no removal flags. All matching documents will be removed.

MONGOC_REMOVE_SINGLE_REMOVE

Only remove the first matching document from the selector.

libmongoc-1.3.1/doc/mongoc_reply_flags_t.page000066400000000000000000000033501264720626300212750ustar00rootroot00000000000000 mongoc_reply_flags_t Flags for deletion operations
Synopsis
Description

These flags correspond to the wire protocol. They may be bitwise or'd together.

Flag Values

MONGOC_REPLY_NONE

No flags set.

MONGOC_REPLY_CURSOR_NOT_FOUND

No matching cursor was found on the server.

MONGOC_REPLY_QUERY_FAILURE

The query failed or was invalid. Error document has been provided.

MONGOC_REPLY_SHARD_CONFIG_STALE

Shard config is stale.

MONGOC_REPLY_AWAIT_CAPABLE

If the returned cursor is capable of MONGOC_QUERY_AWAIT_DATA.

libmongoc-1.3.1/doc/mongoc_server_description_destroy.page000066400000000000000000000021611264720626300241240ustar00rootroot00000000000000 mongoc_server_description_destroy()
Synopsis
Parameters

description

A The description to destroy..

Description

This function cleans up all memory associated with the given server description.

Returns

None.

libmongoc-1.3.1/doc/mongoc_server_description_host.page000066400000000000000000000024551264720626300234160ustar00rootroot00000000000000 mongoc_server_description_host()
Synopsis
Parameters

description

A The server description for which we'd like a host.

Description

This function returns the host that the given server description is associated with. This object is owned by the server description

Returns

A reference to the given server description's mongoc_host_list_t.

libmongoc-1.3.1/doc/mongoc_server_description_id.page000066400000000000000000000022331264720626300230270ustar00rootroot00000000000000 mongoc_server_description_id()
Synopsis
Parameters

description

A The server description whose id we want.

Description

This functionr returns the server id for the given server description.

Returns

A uint32_t id for the given server description.

libmongoc-1.3.1/doc/mongoc_server_description_new_copy.page000066400000000000000000000024041264720626300242560ustar00rootroot00000000000000 mongoc_server_description_new_copy()
Synopsis
Parameters

description

A The server description to copy.

Description

This function copies the given server description and returns a new server description object. The caller is responsible for destroying the new copy.

Returns

A copy of the original server description.

libmongoc-1.3.1/doc/mongoc_server_description_t.page000066400000000000000000000021121264720626300226720ustar00rootroot00000000000000 mongoc_server_description_t Server description
Synopsis typedef struct _mongoc_server_description_t mongoc_server_description_t]]>

mongoc_server_description_t holds information about a mongod server to which the driver has connected.

Lifecycle

It is required that this object be cleaned up with mongoc_server_description_destroy().

Functions
libmongoc-1.3.1/doc/mongoc_socket_accept.page000066400000000000000000000027101264720626300212510ustar00rootroot00000000000000 mongoc_socket_accept()
Synopsis
Parameters

sock

A mongoc_socket_t.

expire_at

An int64_t containing a timeout in milliseconds.

Description

This function is a wrapper around the BSD socket accept() interface. It allows for more portability between UNIX-like and Microsoft Windows platforms.

Returns

NULL upon failure to accept or timeout. A newly allocated mongoc_socket_t that should be released with mongoc_socket_destroy() on success.

libmongoc-1.3.1/doc/mongoc_socket_bind.page000066400000000000000000000025701264720626300207320ustar00rootroot00000000000000 mongoc_socket_bind()
Synopsis
Parameters

sock

A mongoc_socket_t.

addr

A struct sockaddr.

addrlen

A socklen_t.

Description

This function is a wrapper around the BSD socket bind() interface. It provides better portability between UNIX-like and Microsoft Windows platforms.

Returns

0 on success, -1 on failure and errno is set.

libmongoc-1.3.1/doc/mongoc_socket_close.page000066400000000000000000000022161264720626300211200ustar00rootroot00000000000000 mongoc_socket_close()
Synopsis
Parameters

socket

A mongoc_socket_t.

Description

This function is a wrapper around the BSD socket shutdown() interface. It provides better portability between UNIX-like and Microsoft Windows platforms.

Returns

0 on success, -1 on failure to close the socket.

libmongoc-1.3.1/doc/mongoc_socket_connect.page000066400000000000000000000035331264720626300214470ustar00rootroot00000000000000 mongoc_socket_connect()
Synopsis
Parameters

sock

A mongoc_socket_t.

addr

A struct sockaddr.

addrlen

A socklen_t.

expire_at

A int64_t containing the absolute timeout using the monotonic clock.

Description

This function is a wrapper around the BSD socket connect() interface. It provides better portability between UNIX-like and Microsoft Windows platforms.

This function performs a socket connection but will fail if @expire_at has been reached by the monotonic clock. Keep in mind that this is an absolute timeout in milliseconds. You should add your desired timeout to bson_get_monotonic_time().

Returns

0 if successful, -1 on failure and errno is set.

libmongoc-1.3.1/doc/mongoc_socket_destroy.page000066400000000000000000000020311264720626300214770ustar00rootroot00000000000000 mongoc_socket_destroy()
Synopsis
Parameters

sock

A mongoc_socket_t.

Description

This function releases all resources associated with a mongoc_socket_t. This should be called when you are no longer using the socket.

libmongoc-1.3.1/doc/mongoc_socket_errno.page000066400000000000000000000022721264720626300211420ustar00rootroot00000000000000 mongoc_socket_errno()
Synopsis
Parameters

sock

A mongoc_socket_t.

Description

This function returns the currently captured errno for a socket. This may be useful to check was the last errno was after another function call has been made that clears the threads errno variable.

Returns

0 if there is no error, otherwise a specific errno.

libmongoc-1.3.1/doc/mongoc_socket_getnameinfo.page000066400000000000000000000022711264720626300223100ustar00rootroot00000000000000 mongoc_socket_getnameinfo()
Synopsis
Parameters

sock

A mongoc_socket_t.

Description

This is a helper around getting the local name of a socket. It is a wrapper around getpeername() and getnameinfo().

Returns

A newly allocated string that should be freed with bson_free().

libmongoc-1.3.1/doc/mongoc_socket_getsockname.page000066400000000000000000000026251264720626300223170ustar00rootroot00000000000000 mongoc_socket_getsockname()
Synopsis
Parameters

sock

A mongoc_socket_t.

addr

A struct sockaddr.

addrlen

A socklen_t.

Description

Retrieves the socket name for sock. The result is stored in addr. addrlen should be the size of the addr when calling this.

Returns

0 if successful, otherwise -1 and errno is set.

libmongoc-1.3.1/doc/mongoc_socket_listen.page000066400000000000000000000023221264720626300213070ustar00rootroot00000000000000 mongoc_socket_listen()
Synopsis
Parameters

sock

A mongoc_socket_t.

backlog

An int containing max backlog size.

Description

This function is similar to the BSD sockets listen() function. It is meant for socket servers.

Returns

0 on success, -1 on failure and errno is set.

libmongoc-1.3.1/doc/mongoc_socket_new.page000066400000000000000000000027601264720626300206100ustar00rootroot00000000000000 mongoc_socket_new()
Synopsis
Parameters

domain

An int containing the address family such as AF_INET.

type

An int containing the socket type such as SOCK_STREAM.

protocol

A protocol subset, typically 0.

Description

Creates a new mongoc_socket_t structure. This calls socket() underneath to create a network socket.

Returns

A new socket if successful, otherwise NULL and errno is set. The result should be freed with mongoc_socket_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_socket_recv.page000066400000000000000000000033371264720626300207570ustar00rootroot00000000000000 mongoc_socket_recv()
Synopsis
Parameters

sock

A mongoc_socket_t.

buf

A buffer to read into.

buflen

A size_t with the number of bytes to receive.

flags

flags for recv().

expire_at

A int64_t with the time to expire in monotonic time using bson_get_monotonic_time(), which is in microseconds.

Description

This function performs a recv() on the underlying socket.

Returns

The number of bytes received on success, 0 on stream closed, and -1 if there was a failure and errno is set.

libmongoc-1.3.1/doc/mongoc_socket_send.page000066400000000000000000000032711264720626300207460ustar00rootroot00000000000000 mongoc_socket_send()
Synopsis
Parameters

sock

A mongoc_socket_t.

buf

A buffer to send.

buflen

A size_t with the number of bytes in buf.

expire_at

A int64_t with an absolute timeout for the operation or 0. The timeout is in monotonic time using microseconds. You can retrieve the current monotonic time with bson_get_monotonic_time().

Description

Sends buflen bytes in buf to the destination. If a timeout expired, the number of bytes sent will be returned or -1 if no bytes were sent.

Returns

-1 on failure and errno is set, or the number of bytes sent.

libmongoc-1.3.1/doc/mongoc_socket_sendv.page000066400000000000000000000033111264720626300211270ustar00rootroot00000000000000 mongoc_socket_sendv()
Synopsis
Parameters

sock

A mongoc_socket_t.

iov

A mongoc_iovec_t.

iovcnt

A size_t containing the number of elements in iov.

expire_at

A int64_t with absolute timeout in monotonic time. The monotonic clock is in microseconds and can be fetched using bson_get_monotonic_time().

Description

Sends a vector of buffers to the destination. This uses sendmsg() when available to perform a gathered write. If IOV_MAX is reached, a fallback will be used.

Returns

the number of bytes sent on success, or -1 on failure and errno is set.

libmongoc-1.3.1/doc/mongoc_socket_setsockopt.page000066400000000000000000000030661264720626300222150ustar00rootroot00000000000000 mongoc_socket_setsockopt()
Synopsis
Parameters

sock

A mongoc_socket_t.

level

A sockopt level.

optname

A sockopt name.

optval

A the value for the sockopt.

optlen

A socklen_t that contains the length of optval.

Description

This is a helper function for setsockopt().

Returns

0 on success, -1 on failure and errno is set.

libmongoc-1.3.1/doc/mongoc_socket_t.page000066400000000000000000000017461264720626300202650ustar00rootroot00000000000000 mongoc_socket_t Portable socket abstraction
Synopsis typedef struct _mongoc_socket_t mongoc_socket_t]]>
Synopsis

This structure provides a socket abstraction that is friendlier for portability than BSD sockets directly. Inconsistencies between Linux, various BSDs, Solaris, and Windows are handled here.

Functions
libmongoc-1.3.1/doc/mongoc_ssl_opt_get_default.page000066400000000000000000000014271264720626300224740ustar00rootroot00000000000000 mongoc_ssl_opt_get_default()
Synopsis
Returns

Returns the default SSL options for the process. This should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_ssl_opt_t.page000066400000000000000000000031701264720626300204510ustar00rootroot00000000000000 mongoc_ssl_opt_t
Synopsis
Description

This structure is used to set the SSL options for a mongoc_client_t or mongoc_client_pool_t.

Beginning in version 1.2.0, once a pool or client has any SSL options set, all connections use SSL, even if "ssl=true" is omitted from the MongoDB URI. Before, SSL options were ignored unless "ssl=true" was included in the URI.

Functions
See Also

mongoc_client_set_ssl_opts

mongoc_client_pool_set_ssl_opts

libmongoc-1.3.1/doc/mongoc_stream_buffered_new.page000066400000000000000000000031361264720626300224530ustar00rootroot00000000000000 mongoc_stream_buffered_new()
Synopsis
Parameters

base_stream

A mongoc_stream_t to buffer.

buffer_size

A size_t containing the desired buffer size.

This function shall create a new mongoc_stream_t that buffers bytes to and from the underlying base_stream.

buffer_size will be used as the initial buffer size. It may grow past this size.

Returns

A newly allocated mongoc_stream_buffered_t on success, otherwise NULL. This should be freed with mongoc_stream_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_stream_buffered_t.page000066400000000000000000000016641264720626300221310ustar00rootroot00000000000000 mongoc_stream_buffered_t
Synopsis
Description

mongoc_stream_buffered_t should be considered a subclass of mongoc_stream_t. It performs buffering on an underlying stream.

See Also

mongoc_stream_buffered_new()

mongoc_stream_destroy()

libmongoc-1.3.1/doc/mongoc_stream_close.page000066400000000000000000000023341264720626300211240ustar00rootroot00000000000000 mongoc_stream_close()
Synopsis
Parameters

stream

A mongoc_stream_t.

This function shall close underlying file-descriptors of stream.

Returns

0 on success, otherwise -1 and errno is set.

See Also

mongoc_stream_destroy()

libmongoc-1.3.1/doc/mongoc_stream_cork.page000066400000000000000000000026551264720626300207630ustar00rootroot00000000000000 mongoc_stream_cork()
Synopsis
Parameters

stream

A mongoc_stream_t.

This function shall prevent the writing of bytes to the underlying socket.

Not all streams implement this function. Buffering generally works better.

Returns

0 on success, -1 on failure and errno is set.

See Also

mongoc_stream_buffered_new().

mongoc_stream_uncork().

libmongoc-1.3.1/doc/mongoc_stream_destroy.page000066400000000000000000000020561264720626300215110ustar00rootroot00000000000000 mongoc_stream_destroy()
Synopsis
Parameters

stream

A mongoc_stream_t.

This function shall release all resources associated with a mongoc_stream_t, including freeing the structure. It is invalid to use stream after calling this function.

libmongoc-1.3.1/doc/mongoc_stream_file_get_fd.page000066400000000000000000000025101264720626300222420ustar00rootroot00000000000000 mongoc_stream_file_get_fd()
Synopsis
Parameters

stream

A mongoc_stream_file_t.

This function shall return the underlying file-descriptor of a mongoc_stream_file_t.

Performing operations on the underlying file-descriptor may not be safe if used in conjunction with buffering. Avoid reading or writing from this file-descriptor.

Returns

A file-descriptor that should not be modified by the caller.

libmongoc-1.3.1/doc/mongoc_stream_file_new.page000066400000000000000000000024321264720626300216060ustar00rootroot00000000000000 mongoc_stream_file_new()
Synopsis
Parameters

fd

A UNIX style file-descriptor.

Creates a new mongoc_stream_file_t using the file-descriptor provided.

Returns

NULL upon failure, otherwise a newly allocated mongoc_stream_file_t that should be freed with mongoc_stream_destroy() when no longer in use.

errno is set upon failure.

libmongoc-1.3.1/doc/mongoc_stream_file_new_for_path.page000066400000000000000000000033071264720626300234720ustar00rootroot00000000000000 mongoc_stream_file_new_for_path()
Synopsis
Parameters

path

The path of the target file.

flags

Flags to be passed to open().

mode

An optional mode to be passed to open() when creating a file.

This function shall create a new mongoc_stream_file_t after opening the underlying file with open() or the platform equivalent.

Returns

NULL on failure, otherwise a newly allocated mongoc_stream_file_t that should be freed with mongoc_stream_destroy() when no longer in use.

errno is set upon failure.

libmongoc-1.3.1/doc/mongoc_stream_file_t.page000066400000000000000000000015131264720626300212570ustar00rootroot00000000000000 mongoc_stream_file_t
Synopsis

mongoc_stream_file_t is a mongoc_stream_t subclass for working with standard UNIX style file-descriptors.

Functions
libmongoc-1.3.1/doc/mongoc_stream_flush.page000066400000000000000000000023751264720626300211450ustar00rootroot00000000000000 mongoc_stream_flush()
Synopsis
Parameters

stream

A mongoc_stream_t.

This function shall flush any buffered bytes in the underlying stream to the physical transport. It mimics the API and semantics of fflush(), forcing a write of user space buffered data.

Not all stream implementations may implement this feature.

Returns

0 is returned on success, otherwise -1 and errno is set.

libmongoc-1.3.1/doc/mongoc_stream_get_base_stream.page000066400000000000000000000024141264720626300231420ustar00rootroot00000000000000 mongoc_stream_get_base_stream()
Synopsis
Parameters

stream

A mongoc_stream_t.

This function shall fetch the underlying stream for streams that wrap a base stream. Such implementations include mongoc_stream_buffered_t and mongoc_stream_tls_t.

Returns

A mongoc_stream_t or NULL.

libmongoc-1.3.1/doc/mongoc_stream_gridfs_new.page000066400000000000000000000024721264720626300221510ustar00rootroot00000000000000 mongoc_stream_gridfs_new()
Synopsis
Parameters

file

A mongoc_gridfs_file_t.

This function shall create a new mongoc_gridfs_file_t. This function does not transfer ownership of file. Therefore, file must remain valid for the lifetime of this stream.

Returns

A newly allocated mongoc_stream_gridfs_t if successful, otherwise NULL.

libmongoc-1.3.1/doc/mongoc_stream_gridfs_t.page000066400000000000000000000016261264720626300216230ustar00rootroot00000000000000 mongoc_stream_gridfs_t
Synopsis

The mongoc_stream_gridfs_t class is an implementation of mongoc_stream_t for files stored in GridFS. It allows for transparently streaming GridFS files from a MongoDB server.

Functions
libmongoc-1.3.1/doc/mongoc_stream_read.page000066400000000000000000000045271264720626300207400ustar00rootroot00000000000000 mongoc_stream_read()
Synopsis
Parameters

stream

A mongoc_stream_t.

buf

The buffer to read into.

count

The number of bytes to read.

min_bytes

The minimum number of bytes to read, or else indicate failure.

timeout_msec

The number of milliseconds to wait before failure, a timeout of 0 will not block. If negative, use the default timeout.

The mongoc_stream_read() function shall perform a read from a mongoc_stream_t. It's modeled on the API and semantics of read(), though the parameters map only loosely.

Returns

The mongoc_stream_read function returns the number of bytes read on success. It returns >= 0 and < min_bytes when end-of-file is encountered and -1 on failure. errno is set upon failure.

See Also

mongoc_stream_readv()

mongoc_stream_write()

mongoc_stream_writev()

libmongoc-1.3.1/doc/mongoc_stream_readv.page000066400000000000000000000041771264720626300211270ustar00rootroot00000000000000 mongoc_stream_readv()
Synopsis
Parameters

stream

A mongoc_stream_t.

iov

A vector of mongoc_iovec_t.

iovcnt

The number of items in iov.

min_bytes

The minimum number of bytes to read or failure will be indicated.

timeout_msec

A timeout in milliseconds, or 0 to indicate non-blocking. A negative value with use the default timeout.

This function is identical to mongoc_stream_read() except that it takes a mongoc_iovec_t to perform gathered I/O.

Returns

>= 0 on success, -1 on failure and errno is set.

See Also

mongoc_stream_read()

mongoc_stream_write()

mongoc_stream_writev()

libmongoc-1.3.1/doc/mongoc_stream_setsockopt.page000066400000000000000000000032751264720626300222220ustar00rootroot00000000000000 mongoc_stream_setsockopt()
Synopsis
Parameters

stream

A mongoc_stream_t.

level

The level to pass to setsockopt().

optname

The optname to pass to setsockopt().

optval

The optval to pass to setsockopt().

optlen

The optlen to pass to setsockopt().

This function is a wrapper around setsockopt() for streams that wrap sockets.

Returns

0 on success, otherwise -1 and errno is set.

libmongoc-1.3.1/doc/mongoc_stream_socket_get_socket.page000066400000000000000000000023041264720626300235130ustar00rootroot00000000000000 mongoc_stream_socket_get_socket()
Synopsis
Parameters

stream

A mongoc_stream_socket_t.

Retrieves the underlying mongoc_socket_t for a mongoc_stream_socket_t.

Returns

A mongoc_stream_socket_t.

libmongoc-1.3.1/doc/mongoc_stream_socket_new.page000066400000000000000000000026361264720626300221650ustar00rootroot00000000000000 mongoc_stream_socket_new()
Synopsis
Parameters

socket

A mongoc_socket_t.

Creates a new mongoc_stream_socket_t using the mongoc_socket_t provided.

This function transfers ownership of socket to the newly allocated stream.

Returns

A newly allocated mongoc_stream_socket_t that should be freed with mongoc_stream_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_stream_socket_t.page000066400000000000000000000015231264720626300216310ustar00rootroot00000000000000 mongoc_stream_socket_t
Synopsis

mongoc_stream_socket_t should be considered a subclass of mongoc_stream_t that works upon socket streams.

Functions
libmongoc-1.3.1/doc/mongoc_stream_t.page000066400000000000000000000034711264720626300202650ustar00rootroot00000000000000 mongoc_stream_t
Synopsis

mongoc_stream_t provides a generic streaming IO abstraction based on a struct of pointers interface. The idea is to allow wrappers, perhaps other language drivers, to easily shim their IO system on top of mongoc_stream_t.

The API for the stream abstraction is currently private and non-extensible.

Stream Types

There are a number of built in stream types that come with mongoc. The default configuration is a buffered unix stream. If SSL is in use, that in turn is wrapped in a tls stream.

Functions
See Also

mongoc_stream_buffered_t

mongoc_stream_file_t

mongoc_stream_socket_t

mongoc_stream_tls_t

mongoc_stream_gridfs_t

libmongoc-1.3.1/doc/mongoc_stream_tls_check_cert.page000066400000000000000000000026441264720626300227770ustar00rootroot00000000000000 mongoc_stream_tls_check_cert()
Synopsis
Parameters

stream

A mongoc_stream_tls_t.

host

A UTF-8 string holding the hostname used in socket creation. This value is what will be matched against the server provided certificate.

The mongoc_stream_tls_check_cert() function shall perform a RFC-6125 certificate verification.

Returns

The mongoc_stream_tls_check_cert() function returns true if the certificate is valid was successful. If false, openssl errors may be set.

libmongoc-1.3.1/doc/mongoc_stream_tls_do_handshake.page000066400000000000000000000024741264720626300233160ustar00rootroot00000000000000 mongoc_stream_tls_do_handshake()
Synopsis
Parameters

stream

A mongoc_stream_tls_t.

timeout_msec

A timeout, in milliseconds, for the handshake.

This function shall perform an SSL handshake on the underlying stream.

Returns

The mongoc_stream_tls_do_handshake() function returns true if the handshake was successful. If false, errno or openssl errors may be set.

libmongoc-1.3.1/doc/mongoc_stream_tls_new.page000066400000000000000000000026011264720626300214670ustar00rootroot00000000000000 mongoc_stream_tls_new()
Synopsis
Parameters

base_stream

A mongoc_stream_t.

opt

A mongoc_ssl_opt_t.

client

1 for client, 0 for server TLS.

Creates a new mongoc_stream_tls_t using the parameters supplied.

Returns

A newly allocated mongoc_stream_tls_t.

libmongoc-1.3.1/doc/mongoc_stream_tls_t.page000066400000000000000000000014651264720626300211500ustar00rootroot00000000000000 mongoc_stream_tls_t
Synopsis

mongoc_stream_tls_t is a mongoc_stream_t subclass for working with OpenSSL TLS streams.

Functions
libmongoc-1.3.1/doc/mongoc_stream_uncork.page000066400000000000000000000027031264720626300213200ustar00rootroot00000000000000 mongoc_stream_uncork()
Synopsis
Parameters

stream

A mongoc_stream_t.

This function shall allow a previously corked socket to pass bytes to the underlying socket.

Not all streams implement this function. Buffering generally works better.

Returns

0 on success, -1 on failure and errno is set.

See Also

mongoc_stream_buffered_new().

mongoc_stream_cork().

libmongoc-1.3.1/doc/mongoc_stream_write.page000066400000000000000000000042621264720626300211530ustar00rootroot00000000000000 mongoc_stream_write()
Synopsis
Parameters

stream

A mongoc_stream_t.

buf

The buffer to write.

count

The number of bytes to write.

timeout_msec

The number of milliseconds to wait before failure, a timeout of 0 will not block. If negative, use the default timeout.

The mongoc_stream_write() function shall perform a write to a mongoc_stream_t. It's modeled on the API and semantics of write(), though the parameters map only loosely.

Returns

The mongoc_stream_write function returns the number of bytes write on success. It returns >= 0 and < min_bytes when end-of-file is encountered and -1 on failure. errno is set upon failure.

See Also

mongoc_stream_read()

mongoc_stream_readv()

mongoc_stream_writev()

libmongoc-1.3.1/doc/mongoc_stream_writev.page000066400000000000000000000034201264720626300213340ustar00rootroot00000000000000 mongoc_stream_writev()
Synopsis
Parameters

stream

A mongoc_stream_t.

iov

A vector of mongoc_iovec_t.

iovcnt

The number of items in iov.

timeout_msec

The number of milliseconds to block before indicating failure, or 0 for non-blocking. Negative values indicate the default timeout.

The mongoc_stream_writev() function shall perform a write to a mongoc_stream_t. It's modeled on the API and semantics of writev(), though the parameters map only loosely.

Returns

The number of bytes written on success, or -1 upon failure and errno is set.

libmongoc-1.3.1/doc/mongoc_update_flags_t.page000066400000000000000000000033561264720626300214320ustar00rootroot00000000000000 mongoc_update_flags_t Flags for deletion operations
Synopsis
Description

These flags correspond to the MongoDB wire protocol. They may be bitwise or'd together. The allow for modifying the way an update is performed in the MongoDB server.

Flag Values

MONGOC_UPDATE_NONE

No update flags set.

MONGOC_UPDATE_UPSERT

If an upsert should be performed.

MONGOC_UPDATE_MULTI_UPDATE

If more than a single matching document should be updated. By default only the first document is updated.

MONGOC_UPDATE_NO_VALIDATE

Do not perform client side BSON validations when performing an update. This is useful if you already know your BSON documents are valid.

libmongoc-1.3.1/doc/mongoc_uri_copy.page000066400000000000000000000021441264720626300202740ustar00rootroot00000000000000 mongoc_uri_copy()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Copies the entire contents of a URI.

Returns

A newly allocated mongoc_uri_t that should be freed with mongoc_uri_destroy().

libmongoc-1.3.1/doc/mongoc_uri_destroy.page000066400000000000000000000016001264720626300210070ustar00rootroot00000000000000 mongoc_uri_destroy()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Frees all resources associated with a uri.

libmongoc-1.3.1/doc/mongoc_uri_get_auth_mechanism.page000066400000000000000000000021111264720626300231400ustar00rootroot00000000000000 mongoc_uri_get_auth_mechanism()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches the authMechanism parameter to an URI if provided.

Returns

A string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_auth_source.page000066400000000000000000000020741264720626300225040ustar00rootroot00000000000000 mongoc_uri_get_auth_source()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches the authSource parameter of an URI if provided.

Returns

A string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_database.page000066400000000000000000000021571264720626300217310ustar00rootroot00000000000000 mongoc_uri_get_database()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches the database portion of an URI if provided. This is the portion after the / but before the ?.

Returns

A string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_hosts.page000066400000000000000000000022401264720626300213160ustar00rootroot00000000000000 mongoc_uri_get_hosts()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches a linked list of hosts that were defined in the URI (the comma-separated host section).

Returns

A linked list of mongoc_host_list_t structures that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_options.page000066400000000000000000000021601264720626300216520ustar00rootroot00000000000000 mongoc_uri_get_options()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches a bson document containing all of the options provided after the ? of a URI.

Returns

A bson_t which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_password.page000066400000000000000000000020261264720626300220220ustar00rootroot00000000000000 mongoc_uri_get_password()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches the password portion of an URI.

Returns

A string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_read_concern.page000066400000000000000000000022771264720626300226120ustar00rootroot00000000000000 mongoc_uri_get_read_concern()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches a read concern that is owned by the URI instance. This read concern is configured based on URI parameters.

Returns

Returns a mongoc_read_concern_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_read_prefs.page000066400000000000000000000026531264720626300223000ustar00rootroot00000000000000 mongoc_uri_get_read_prefs()
Synopsis
Deprecated

This function is deprecated and should not be used in new code.

Please use mongoc_uri_get_read_prefs_t() instead.

Parameters

uri

A mongoc_uri_t.

Description

Fetches a bson document containing read preference tag information from a URI. Note that this does not include the read preference mode.

Returns

Returns a bson document that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_read_prefs_t.page000066400000000000000000000023071264720626300226170ustar00rootroot00000000000000 mongoc_uri_get_read_prefs_t()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches a read preference that is owned by the URI instance. This read preference concern is configured based on URI parameters.

Returns

Returns a mongoc_read_prefs_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_replica_set.page000066400000000000000000000020711264720626300224520ustar00rootroot00000000000000 mongoc_uri_get_replica_set()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches the replicaSet parameter of an URI.

Returns

Returns a string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_ssl.page000066400000000000000000000020521264720626300207600ustar00rootroot00000000000000 mongoc_uri_get_ssl()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches a boolean indicating if SSL was specified for use in the URI.

Returns

Returns a boolean, true indicating that SSL should be used.

libmongoc-1.3.1/doc/mongoc_uri_get_string.page000066400000000000000000000020161264720626300214650ustar00rootroot00000000000000 mongoc_uri_get_string()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches the URI as a string.

Returns

Returns a string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_username.page000066400000000000000000000020361264720626300220000ustar00rootroot00000000000000 mongoc_uri_get_username()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches the username portion of a URI.

Returns

Returns a string which should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_get_write_concern.page000066400000000000000000000023071264720626300230230ustar00rootroot00000000000000 mongoc_uri_get_write_concern()
Synopsis
Parameters

uri

A mongoc_uri_t.

Description

Fetches a write concern that is owned by the URI instance. This write concern is configured based on URI parameters.

Returns

Returns a mongoc_write_concern_t that should not be modified or freed.

libmongoc-1.3.1/doc/mongoc_uri_new.page000066400000000000000000000040341264720626300201130ustar00rootroot00000000000000 mongoc_uri_new()
Synopsis
Parameters

uri_string

A string containing a URI.

Description

Parses a string containing a MongoDB style URI connection string.

Returns

A newly allocated mongoc_uri_t if successful. Otherwise NULL.

Failure to handle the result of this function is a programming error.

Examples

Examples of some valid MongoDB connection strings can be seen below.

"mongodb://localhost/"

"mongodb://localhost/?replicaSet=myreplset"

"mongodb://myuser:mypass@localhost/"

"mongodb://kerberosuser%40EXAMPLE.COM@example.com/?authMechanism=GSSAPI"

"mongodb://[::1]:27017/"

"mongodb://10.0.0.1:27017,10.0.0.1:27018,[::1]:27019/?ssl=true"

"mongodb:///tmp/mongodb-27017.sock"

"mongodb://localhost,[::1]/mydb?authSource=mydb"

libmongoc-1.3.1/doc/mongoc_uri_new_for_host_port.page000066400000000000000000000025131264720626300230620ustar00rootroot00000000000000 mongoc_uri_new_for_host_port()
Synopsis
Parameters

hostname

A string containing the hostname.

port

A uint16_t.

Description

Creates a new mongoc_uri_t based on the hostname and port provided.

Returns

Returns a newly allocated mongoc_uri_t that should be freed with mongoc_uri_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_uri_t.page000066400000000000000000000304511264720626300175670ustar00rootroot00000000000000 mongoc_uri_t
Synopsis
Description

mongoc_uri_t provides an abstraction on top of the MongoDB connection URI format. It provides standardized parsing as well as convenience methods for extracting useful information such as replica hosts or authorization information.

See Connection String URI Reference on the MongoDB website for more information.

Format [username:password@] <2> host1 <3> [:port1] <4> [,host2[:port2],...[,hostN[:portN]]] <5> [/[database] <6> [?options]] <7> ]]>

mongodb is the specifier of the MongoDB protocol.

An optional username and password.

The only required part of the uri. This specifies either a hostname, IP address or UNIX domain socket.

An optional port number. Defaults to :27017.

Extra optional hosts and ports. You would specify multiple hosts, for example, for connections to replica sets.

The name of the database to authenticate if the connection string includes authentication credentials. If /database is not specified and the connection string includes credentials, defaults to the 'admin' database.

Connection specific options.

Replica Set Example

To describe a connection to a replica set named 'test' with the following mongod hosts:

db1.example.com on port 27017

db2.example.com on port 2500

You would use the connection string that resembles the following.

mongodb://db1.example.com,db2.example.com:2500/?replicaSet=test
Connection Options

ssl

{true|false}, indicating if SSL must be used. (See also mongoc_client_set_ssl_opts and mongoc_client_pool_set_ssl_opts.)

connectTimeoutMS

A timeout in milliseconds to attempt a connection before timing out. This setting applies to server discovery and monitoring connections as well as to connections for application operations. The default is 10 seconds.

socketTimeoutMS

The time in milliseconds to attempt to send or receive on a socket before the attempt times out. The default is 5 minutes.

Setting any of the *TimeoutMS options above to 0 will be interpreted as "use the default value"

Server Discovery, Monitoring, and Selection Options

Clients in a mongoc_client_pool_t share a topology scanner that runs on a background thread. The thread wakes every heartbeatFrequencyMS (default 10 seconds) to scan all MongoDB servers in parallel. Whenever an application operation requires a server that is not known--for example, if there is no known primary and your application attempts an insert--the thread rescans all servers every half-second. In this situation the pooled client waits up to serverSelectionTimeoutMS (default 30 seconds) for the thread to find a server suitable for the operation, then returns an error with domain MONGOC_ERROR_SERVER_SELECTION.

Technically, the total time an operation may wait while a pooled client scans the topology is controlled both by serverSelectionTimeoutMS and connectTimeoutMS. The longest wait occurs if the last scan begins just at the end of the selection timeout, and a slow or down server requires the full connection timeout before the client gives up.

A non-pooled client is single-threaded. Every heartbeatFrequencyMS, it blocks the next application operation while it does a parallel scan. This scan takes as long as needed to check the slowest server: roughly connectTimeoutMS. Therefore the default heartbeatFrequencyMS for single-threaded clients is greater than for pooled clients: 60 seconds.

By default, single-threaded (non-pooled) clients scan only once when an operation requires a server that is not known. If you attempt an insert and there is no known primary, the client checks all servers once trying to find it, then succeeds or returns an error with domain MONGOC_ERROR_SERVER_SELECTION. But if you set serverSelectionTryOnce to "false", the single-threaded client loops, checking all servers every half-second, until serverSelectionTimeoutMS.

The total time an operation may wait for a single-threaded client to scan the topology is determined by connectTimeoutMS in the try-once case, or serverSelectionTimeoutMS and connectTimeoutMS if serverSelectionTryOnce is set "false".

heartbeatFrequencyMS

The interval between server monitoring checks. Defaults to 10 seconds in pooled (multi-threaded) mode, 60 seconds in non-pooled mode (single-threaded).

serverSelectionTimeoutMS

A timeout in milliseconds to block for server selection before throwing an exception. The default is 30 seconds.

serverSelectionTryOnce

If "true", the driver scans the topology exactly once after server selection fails, then either selects a server or returns an error. If it is false, then the driver repeatedly searches for a suitable server for up to serverSelectionTimeoutMS milliseconds (pausing a half second between attempts). The default for serverSelectionTryOnce is "false" for pooled clients, otherwise "true".

Pooled clients ignore serverSelectionTryOnce; they signal the thread to rescan the topology every half-second until serverSelectionTimeoutMS expires.

socketCheckIntervalMS

Only applies to single threaded clients. If a socket has not been used within this time, its connection is checked with a quick "isMaster" call before it is used again. Defaults to 5 seconds.

Setting any of the *TimeoutMS options above to 0 will be interpreted as "use the default value"

Connection Pool Options

maxPoolSize

The maximum number of connections in the pool. The default value is 100.

minPoolSize

The minimum number of connections in the connection pool. Default value is 0. These are lazily created.

maxIdleTimeMS

Not implemented.

waitQueueMultiple

Not implemented.

waitQueueTimeoutMS

Not implemented.

Write Concern Options

w

0

The driver will not acknowledge write operations but will pass or handle any network and socket errors that it receives to the client. If you disable write concern but enable the getLastError command’s w option, w overrides the w option.

1

Provides basic acknowledgment of write operations. By specifying 1, you require that a standalone mongod instance, or the primary for replica sets, acknowledge all write operations. For drivers released after the default write concern change, this is the default write concern setting.

majority

For replica sets, if you specify the special majority value to w option, write operations will only return successfully after a majority of the configured replica set members have acknowledged the write operation.

n

For replica sets, if you specify a number n greater than 1, operations with this write concern return only after n members of the set have acknowledged the write. If you set n to a number that is greater than the number of available set members or members that hold data, MongoDB will wait, potentially indefinitely, for these members to become available.

tags

For replica sets, you can specify a tag set to require that all members of the set that have these tags configured return confirmation of the write operation.

wtimeoutMS

The time in milliseconds to wait for replication to succeed, as specified in the w option, before timing out. When wtimeoutMS is 0, write operations will never time out.

journal

Controls whether write operations will wait until the mongod acknowledges the write operations and commits the data to the on disk journal.

true

Enables journal commit acknowledgment write concern. Equivalent to specifying the getLastError command with the j option enabled.

false

Does not require that mongod commit write operations to the journal before acknowledging the write operation. This is the default option for the journal parameter.

Read Concern Options

readConcernLevel

The level of isolation for read operations. If the level is left unspecified, the server default will be used. See the readConcern in the MongoDB Manual for details.

Read Preference Options

readPreference

Specifies the replica set read preference for this connection. This setting overrides any slaveOk value. The read preference values are the following:

primary

primaryPreferred

secondary

secondaryPreferred

nearest

readPreferenceTags

Specifies a tag set as a comma-seperated list of colon-separted key-value pairs.

Functions
libmongoc-1.3.1/doc/mongoc_uri_unescape.page000066400000000000000000000021221264720626300211210ustar00rootroot00000000000000 mongoc_uri_unescape()
Synopsis
Parameters

escaped_string

A utf8 encoded string.

Description

Unescapes an URI encoded string. For example, "%40" would become "@".

Returns

Returns a newly allocated string that should be freed with bson_free().

libmongoc-1.3.1/doc/mongoc_version.page.in000066400000000000000000000024621264720626300205400ustar00rootroot00000000000000 Version Checks Conditional compilation based on mongoc version

The following preprocessor macros can be used to perform various checks based on the version of the library you are compiling against. This may be useful if you only want to enable a feature on a certain version of the library.

#define MONGOC_MAJOR_VERSION (@MONGOC_RELEASED_MAJOR_VERSION@) #define MONGOC_MINOR_VERSION (@MONGOC_RELEASED_MINOR_VERSION@) #define MONGOC_MICRO_VERSION (@MONGOC_RELEASED_MICRO_VERSION@) #define MONGOC_VERSION_S "@MONGOC_RELEASED_VERSION@" #define MONGOC_VERSION_HEX ((1 << 24) | (0 << 16) | (0 << 8) | 0) #define MONGOC_CHECK_VERSION(major, minor, micro) ]]> Compile-Time Version Check Only compile a block on MongoDB C Driver 1.1.0 and newer. Run-Time Version Checks
libmongoc-1.3.1/doc/mongoc_write_concern_copy.page000066400000000000000000000023761264720626300223450ustar00rootroot00000000000000 mongoc_write_concern_copy()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

Description

Performs a deep copy of write_concern.

Returns

Returns a newly allocated copy of write_concern that should be freed with mongoc_write_concern_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_write_concern_destroy.page000066400000000000000000000017601264720626300230600ustar00rootroot00000000000000 mongoc_write_concern_destroy()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

Description

Frees all resources associated with the write concern structure.

libmongoc-1.3.1/doc/mongoc_write_concern_get_fsync.page000066400000000000000000000022471264720626300233510ustar00rootroot00000000000000 mongoc_write_concern_get_fsync()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

Description

Fetches if an fsync should be performed before returning success on a write operation.

Returns

Returns true if fsync is set as part of the write concern.

libmongoc-1.3.1/doc/mongoc_write_concern_get_journal.page000066400000000000000000000022001264720626300236660ustar00rootroot00000000000000 mongoc_write_concern_get_journal()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

Description

Fetches if the write should be journaled before indicating success.

Returns

Returns true if the write should be journaled.

libmongoc-1.3.1/doc/mongoc_write_concern_get_w.page000066400000000000000000000022511264720626300224700ustar00rootroot00000000000000 mongoc_write_concern_get_w()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

Description

Fetches the w parameter of the write concern.

Returns

Returns an integer containing the w value. If wmajority is set, this would be MONGOC_WRITE_CONCERN_W_MAJORITY.

libmongoc-1.3.1/doc/mongoc_write_concern_get_wmajority.page000066400000000000000000000022171264720626300242510ustar00rootroot00000000000000 mongoc_write_concern_get_wmajority()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

Description

Fetches if the write should be written to a majority of nodes before indicating success.

Returns

Returns true if wmajority is set.

libmongoc-1.3.1/doc/mongoc_write_concern_get_wtag.page000066400000000000000000000022711264720626300231660ustar00rootroot00000000000000 mongoc_write_concern_get_wtag()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

Description

A string containing the wtag setting if it has been set. Otherwise returns NULL.

Returns

Returns a string which should not be modified or freed, or NULL.

libmongoc-1.3.1/doc/mongoc_write_concern_get_wtimeout.page000066400000000000000000000024171264720626300241030ustar00rootroot00000000000000 mongoc_write_concern_get_wtimeout()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

Description

Fetches the write timeout to use as part of the write concern. If the write has not completed before this timeout, an error will be returned.

A value of 0 indicates no write timeout.

Returns

Returns an 32-bit signed integer containing the timeout.

libmongoc-1.3.1/doc/mongoc_write_concern_new.page000066400000000000000000000016061264720626300221570ustar00rootroot00000000000000 mongoc_write_concern_new()
Synopsis
Returns

Creates a newly allocated write concern that can be configured based on user preference. This should be freed with mongoc_write_concern_destroy() when no longer in use.

libmongoc-1.3.1/doc/mongoc_write_concern_set_fsync.page000066400000000000000000000026241264720626300233640ustar00rootroot00000000000000 mongoc_write_concern_set_fsync()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

fsync_

A boolean.

Description

Sets if a fsync must be performed before indicating write success.

Deprecated

The fsync write concern is deprecated.

Please use mongoc_write_concern_set_journal() instead.

libmongoc-1.3.1/doc/mongoc_write_concern_set_journal.page000066400000000000000000000022061264720626300237100ustar00rootroot00000000000000 mongoc_write_concern_set_journal()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

journal

A boolean.

Description

Sets if the write must have been journaled before indicating success.

libmongoc-1.3.1/doc/mongoc_write_concern_set_w.page000066400000000000000000000023321264720626300225040ustar00rootroot00000000000000 mongoc_write_concern_set_w()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

w

A positive int32_t or zero.

Description

Sets the w value for the write concern. See mongoc_write_concern_t for more information on this setting.

libmongoc-1.3.1/doc/mongoc_write_concern_set_wmajority.page000066400000000000000000000026631264720626300242720ustar00rootroot00000000000000 mongoc_write_concern_set_wmajority()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

wtimeout_msec

A positive int32_t or zero.

Description

Sets if the write must have been propagated to a majority of nodes before indicating write success.

The timeout specifies how long, in milliseconds, the server should wait before indicating that the write has failed. This is not the same as a socket timeout. A value of zero may be used to indicate no timeout.

libmongoc-1.3.1/doc/mongoc_write_concern_set_wtag.page000066400000000000000000000025071264720626300232040ustar00rootroot00000000000000 mongoc_write_concern_set_wtag()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

tag

A string containing the write tag.

Description

Sets the write tag that must be satistified for the write to indicate success. Write tags are preset write concerns configured on your MongoDB server. See mongoc_write_concern_t for more information on this setting.

libmongoc-1.3.1/doc/mongoc_write_concern_set_wtimeout.page000066400000000000000000000024651264720626300241220ustar00rootroot00000000000000 mongoc_write_concern_set_wtimeout()
Synopsis
Parameters

write_concern

A mongoc_write_concern_t.

wtimeout_msec

A positive int32_t or zero.

Description

Set the timeout in milliseconds that the server should wait before indicating that the write has failed. This is not the same as a socket timeout. A value of zero may be used to indicate no timeout.

libmongoc-1.3.1/doc/mongoc_write_concern_t.page000066400000000000000000000051731264720626300216340ustar00rootroot00000000000000 mongoc_write_concern_t Write Concern abstraction
Synopsis

mongoc_write_concern_t tells the driver what level of acknowledgment to await from the server. The default, MONGOC_WRITE_CONCERN_W_DEFAULT, is right for the great majority of applications.

You can specify a write concern on connection objects, database objects, collection objects, or per-operation.

See Write Concern on the MongoDB website for more information.

Write Concern Levels Network Related

MONGOC_WRITE_CONCERN_W_DEFAULT (1)

By default, writes block awaiting acknowledgment from MongoDB. Acknowledged write concern allows clients to catch network, duplicate key, and other errors.

MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED (0)

With this write concern, MongoDB does not acknowledge the receipt of write operation. Unacknowledged is similar to errors ignored; however, mongoc attempts to receive and handle network errors when possible.

MONGOC_WRITE_CONCERN_W_MAJORITY (majority)

Block until a write has been propagated to a majority of the nodes in the replica set.

n

Block until a write has been propagated to at least n nodes in the replica set.

Node Persistence

journal

Block until the node receiving the write has committed the journal.

Deprecation

The write concern MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED (value -1) is a deprecated synonym for MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED (value 0), and will be removed in the next major release.

Functions
libmongoc-1.3.1/doc/tutorial.page000066400000000000000000000725201264720626300167510ustar00rootroot00000000000000 Tutorial

This guide offers a brief introduction to the MongoDB C Driver.

For more information on the C API, please refer to the API Documentation.

0. Installing

For detailed instructions on installing the MongoDB C Driver on a particular platform, please see the installation guide.

1. Starting MongoDB

To run the examples in this tutorial, MongoDB must be installed and running on localhost on the default port, 27017. To check if it is up and running, connect to it with the MongoDB shell.

$ mongo --host localhost --port 27017 MongoDB shell version: 3.0.6 connecting to: localhost:27017/test >
2. Making a Connection

The C Driver provides a convenient way to access MongoDB -- regardless of cluster configuration -- via a mongoc_client_t. It transparently connects to standalone servers, replica sets and sharded clusters on demand. Once a connection has been made, handles to databases and collections can be obtained via the structs mongoc_database_t and mongoc_collection_t, respectively. MongoDB operations can then be performed through these handles.

At the start of an application, call mongoc_init() before any other libmongoc functions and call mongoc_cleanup() before exiting. When creating handles to clients, databases and servers, call the appropriate destroy functions when finished.

The example below establishes a connection to a standalone server on localhost and performs a simple command. More information about database operations can be found in the CRUD Operations and Executing Commands sections. Examples of connecting to replica sets and sharded clusters can be found on the Advanced Connections page.

<file>connect.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_database_t *database; mongoc_collection_t *collection; bson_t *command, reply, *insert; bson_error_t error; char *str; bool retval; /* * Required to initialize libmongoc's internals */ mongoc_init (); /* * Create a new client instance */ client = mongoc_client_new ("mongodb://localhost:27017"); /* * Get a handle on the database "db_name" and collection "coll_name" */ database = mongoc_client_get_database (client, "db_name"); collection = mongoc_client_get_collection (client, "db_name", "coll_name"); /* * Do work. This example pings the database, prints the result as JSON and * performs an insert */ command = BCON_NEW ("ping", BCON_INT32 (1)); retval = mongoc_client_command_simple (client, "admin", command, NULL, &reply, &error); if (!retval) { fprintf (stderr, "%s\n", error.message); return EXIT_FAILURE; } str = bson_as_json (&reply, NULL); printf ("%s\n", str); insert = BCON_NEW ("hello", BCON_UTF8 ("world")); if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, insert, NULL, &error)) { fprintf (stderr, "%s\n", error.message); } bson_destroy (insert); bson_destroy (&reply); bson_destroy (command); bson_free (str); /* * Release our handles and clean up libmongoc */ mongoc_collection_destroy (collection); mongoc_database_destroy (database); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

On a UNIX-like system, the code can be compiled and run like so:

$ gcc -o connect connect.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./connect { "ok" : 1.000000 }

Alternatively, if pkg-config is not available, paths and libraries can be managed manually.

$ gcc -o connect connect.c -I/usr/local/include -lmongoc-1.0 -lbson-1.0 $ ./connect { "ok" : 1.000000 }

For Windows users, the code can be compiled and run with the following commands. (This assumes that the MongoDB C Driver has been installed to C:\mongo-c-driver; change the include directory as needed.)

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 connect.c C:\> connect { "ok" : 1.000000 }
3. Creating BSON Documents

Documents are stored in MongoDB's data format, BSON. The C driver uses libbson to create BSON documents. There are several ways to construct them: appending key-value pairs, using BCON, or parsing JSON.

Appending BSON

A BSON document, represented as a bson_t in code, can be constructed one field at a time using libbson's append functions.

int main (int argc, char *argv[]) { bson_t *document; bson_t child; char *str; document = bson_new (); /* * Append {"hello" : "world"} to the document. * Passing -1 for the length argument tells libbson to calculate the string length. */ bson_append_utf8 (document, "hello", -1, "world", -1); /* * For convenience, this macro is equivalent. */ BSON_APPEND_UTF8 (document, "hello", "world"); /* * Begin a subdocument. */ BSON_APPEND_DOCUMENT_BEGIN (document, "subdoc", &child); BSON_APPEND_UTF8 (&child, "subkey", "value"); bson_append_document_end (document, &child); /* * Print the document as a JSON string. */ str = bson_as_json (document, NULL); printf ("%s\n", str); bson_free (str); /* * Clean up allocated bson documents. */ bson_destroy (document); return 0; } ]]>

See the libbson documentation for all of the types that can be appended to a bson_t.

Using BCON

BSON C Object Notation, BCON for short, is an alternative way of constructing BSON documents in a manner closer to the intended format. It has less type-safety than BSON's append functions but results in less code.

#include #include int main (int argc, char *argv[]) { bson_t *doc; char *str; doc = BCON_NEW ("name", BCON_UTF8 ("Babe Ruth"), "statistics", "{", "batting_average", BCON_DOUBLE (.342), "hits", BCON_INT32 (2873), "home_runs", BCON_INT32 (714), "rbi", BCON_INT32 (2213), "}", "nicknames", "[", BCON_UTF8 ("the Sultan of Swat"), BCON_UTF8 ("the Bambino"), "]"); str = bson_as_json (doc, NULL); printf ("%s\n", str); bson_free (str); bson_destroy (doc); return 0; } ]]>

Notice that BCON can create arrays, subdocuments and arbitrary fields.

Creating BSON from JSON

For single documents, BSON can be created from JSON strings via bson_new_from_json.

To initialize BSON from a sequence of JSON documents, use bson_json_reader_t.

int main (int argc, char *argv[]) { bson_error_t error; bson_t *bson; char *string; const char *json = "{\"hello\": \"world\"}"; bson = bson_new_from_json ((const uint8_t *)json, -1, &error); if (!bson) { fprintf (stderr, "%s\n", error.message); return EXIT_FAILURE; } string = bson_as_json (bson, NULL); printf ("%s\n", string); bson_free (string); return 0; } ]]>
4. Basic CRUD Operations

This section demonstrates the basics of using the C Driver to interact with MongoDB.

Inserting a Document

To insert documents into a collection, first obtain a handle to a mongoc_collection_t via a mongoc_client_t. Then, use mongoc_collection_insert() to add BSON documents to the collection. This example inserts into the database "mydb" and collection "mycoll".

When finished, ensure that allocated structures are freed by using their respective destroy functions.

<file>insert.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; bson_error_t error; bson_oid_t oid; bson_t *doc; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); doc = bson_new (); bson_oid_init (&oid, NULL); BSON_APPEND_OID (doc, "_id", &oid); BSON_APPEND_UTF8 (doc, "hello", "world"); if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) { fprintf (stderr, "%s\n", error.message); } bson_destroy (doc); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o insert insert.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./insert

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 insert.c C:\> insert

To verify that the insert succeeded, connect with the MongoDB shell.

$ mongo MongoDB shell version: 3.0.6 connecting to: test > use mydb switched to db mydb > db.mycoll.find() { "_id" : ObjectId("55ef43766cb5f36a3bae6ee4"), "hello" : "world" } >
Finding a Document

To query a MongoDB collection with the C driver, use the function mongoc_collection_find(). This returns a cursor to the matching documents. The following examples iterate through the result cursors and print the matches to stdout as JSON strings.

Note that mongoc_collection_find uses a document as a query specifier; for example,

{ "color" : "red" }

will match any document with a field named "color" with value "red". An empty document {} can be used to match all documents.

This first example uses an empty query specifier to find all documents in the database "mydb" and collection "mycoll".

<file>find.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; const bson_t *doc; bson_t *query; char *str; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); query = bson_new (); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL); while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_json (doc, NULL); printf ("%s\n", str); bson_free (str); } bson_destroy (query); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o find find.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./find { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 find.c C:\> find { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

To look for a specific document, add a specifier to query. This example adds a call to BSON_APPEND_UTF8() to look for all documents matching {"hello" : "world"}.

<file>find-specific.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; const bson_t *doc; bson_t *query; char *str; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); query = bson_new (); BSON_APPEND_UTF8 (query, "hello", "world"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL); while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_json (doc, NULL); printf ("%s\n", str); bson_free (str); } bson_destroy (query); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]> $ gcc -o find-specific find-specific.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./find-specific { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" } C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 find-specific.c C:\> find-specific { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }
Updating a Document

This code snippet gives an example of using mongoc_collection_update() to update the fields of a document.

Using the "mydb" database, the following example inserts an example document into the "mycoll" collection. Then, using its _id field, the document is updated with different values and a new field.

<file>update.c</file> #include #include #include int main (int argc, char *argv[]) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; bson_oid_t oid; bson_t *doc = NULL; bson_t *update = NULL; bson_t *query = NULL; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); bson_oid_init (&oid, NULL); doc = BCON_NEW ("_id", BCON_OID (&oid), "key", BCON_UTF8 ("old_value")); if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) { fprintf (stderr, "%s\n", error.message); goto fail; } query = BCON_NEW ("_id", BCON_OID (&oid)); update = BCON_NEW ("$set", "{", "key", BCON_UTF8 ("new_value"), "updated", BCON_BOOL (true), "}"); if (!mongoc_collection_update (collection, MONGOC_UPDATE_NONE, query, update, NULL, &error)) { fprintf (stderr, "%s\n", error.message); goto fail; } fail: if (doc) bson_destroy (doc); if (query) bson_destroy (query); if (update) bson_destroy (update); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o update update.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./update

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 update.c C:\> update { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

To verify that the update succeeded, connect with the MongoDB shell.

$ mongo MongoDB shell version: 3.0.6 connecting to: test > use mydb switched to db mydb > db.mycoll.find({"updated" : true}) { "_id" : ObjectId("55ef549236fe322f9490e17b"), "updated" : true, "key" : "new_value" } >
Deleting a Document

This example illustrates the use of mongoc_collection_remove() to delete documents.

The following code inserts a sample document into the database "mydb" and collection "mycoll". Then, it deletes all documents matching {"hello" : "world"}.

<file>delete.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; bson_error_t error; bson_oid_t oid; bson_t *doc; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "test", "test"); doc = bson_new (); bson_oid_init (&oid, NULL); BSON_APPEND_OID (doc, "_id", &oid); BSON_APPEND_UTF8 (doc, "hello", "world"); if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) { fprintf (stderr, "Insert failed: %s\n", error.message); } bson_destroy (doc); doc = bson_new (); BSON_APPEND_OID (doc, "_id", &oid); if (!mongoc_collection_remove (collection, MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) { fprintf (stderr, "Delete failed: %s\n", error.message); } bson_destroy (doc); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o delete delete.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./delete

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 delete.c C:\> delete

Use the MongoDB shell to prove that the documents have been removed successfully.

$ mongo MongoDB shell version: 3.0.6 connecting to: test > use mydb switched to db mydb > db.mycoll.count({"hello" : "world"}) 0 >
Counting Documents

Counting the number of documents in a MongoDB collection is similar to performing a find operation. This example counts the number of documents matching {"hello" : "world"} in the database "mydb" and collection "mycoll".

<file>count.c</file> #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; bson_error_t error; bson_t *doc; int64_t count; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); doc = bson_new_from_json ((const uint8_t *)"{\"hello\" : \"world\"}", -1, &error); count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); if (count < 0) { fprintf (stderr, "%s\n", error.message); } else { printf ("%" PRId64 "\n", count); } bson_destroy (doc); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o count count.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./count 1

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 count.c C:\> count 1
5. Executing Commands

The driver provides helper functions for executing MongoDB commands on client, database and collection structures. These functions return cursors; the _simple variants return booleans indicating success or failure.

This example executes the collStats command against the collection "mycoll" in database "mydb".

<file>executing.c</file> #include #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; bson_error_t error; bson_t *command; bson_t reply; char *str; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); command = BCON_NEW ("collStats", BCON_UTF8 ("mycoll")); if (mongoc_collection_command_simple (collection, command, NULL, &reply, &error)) { str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); } else { fprintf (stderr, "Failed to run command: %s\n", error.message); } bson_destroy (command); bson_destroy (&reply); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o executing executing.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./executing { "ns" : "mydb.mycoll", "count" : 1, "size" : 48, "avgObjSize" : 48, "numExtents" : 1, "storageSize" : 8192, "lastExtentSize" : 8192.000000, "paddingFactor" : 1.000000, "userFlags" : 1, "capped" : false, "nindexes" : 1, "indexDetails" : { }, "totalIndexSize" : 8176, "indexSizes" : { "_id_" : 8176 }, "ok" : 1.000000 }

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 executing.c C:\> executing { "ns" : "mydb.mycoll", "count" : 1, "size" : 48, "avgObjSize" : 48, "numExtents" : 1, "storageSize" : 8192, "lastExtentSize" : 8192.000000, "paddingFactor" : 1.000000, "userFlags" : 1, "capped" : false, "nindexes" : 1, "indexDetails" : { }, "totalIndexSize" : 8176, "indexSizes" : { "_id_" : 8176 }, "ok" : 1.000000 }
6. Threading

The MongoDB C Driver is thread-unaware in the vast majority of its operations. This means it is up to the programmer to guarantee thread-safety.

However, mongoc_client_pool_t is thread-safe and is used to fetch a mongoc_client_t in a thread-safe manner. After retrieving a client from the pool, the client structure should be considered owned by the calling thread. When the thread is finished, the client should be placed back into the pool.

#include #define N_THREADS 10 static void * worker (void *data) { mongoc_client_pool_t *pool = data; mongoc_client_t *client; client = mongoc_client_pool_pop (pool); /* Do something... */ mongoc_client_pool_push (pool, client); return NULL; } int main (int argc, char *argv[]) { mongoc_client_pool_t *pool; mongoc_uri_t *uri; pthread_t threads[N_THREADS]; mongoc_init (); uri = mongoc_uri_new ("mongodb://localhost/"); pool = mongoc_client_pool_new (uri); for (i = 0; i < N_THREADS; i++) { pthread_create (&threads[i], NULL, worker, pool); } for (i = 0; i < N_THREADS; i++) { pthread_join (threads[i], NULL); } mongoc_client_pool_destroy (pool); mongoc_uri_destroy (uri); mongoc_cleanup (); return 0; } ]]>
7. Next Steps

To find information on advanced topics, browse the rest of the C driver guide or the official MongoDB documentation.

For help with common issues, consult the Troubleshooting page. To report a bug or request a new feature, follow these instructions.

libmongoc-1.3.1/doc/updating-document.page000066400000000000000000000055421264720626300205350ustar00rootroot00000000000000 Updating a Document

This code snippet gives an example of using mongoc_collection_update() to update the fields of a document.

Using the "mydb" database, the following example inserts an example document into the "mycoll" collection. Then, using its _id field, the document is updated with different values and a new field.

<file>update.c</file> #include #include #include int main (int argc, char *argv[]) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; bson_oid_t oid; bson_t *doc = NULL; bson_t *update = NULL; bson_t *query = NULL; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017/"); collection = mongoc_client_get_collection (client, "mydb", "mycoll"); bson_oid_init (&oid, NULL); doc = BCON_NEW ("_id", BCON_OID (&oid), "key", BCON_UTF8 ("old_value")); if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) { printf ("%s\n", error.message); goto fail; } query = BCON_NEW ("_id", BCON_OID (&oid)); update = BCON_NEW ("$set", "{", "key", BCON_UTF8 ("new_value"), "updated", BCON_BOOL (true), "}"); if (!mongoc_collection_update (collection, MONGOC_UPDATE_NONE, query, update, NULL, &error)) { printf ("%s\n", error.message); goto fail; } fail: if (doc) bson_destroy (doc); if (query) bson_destroy (query); if (update) bson_destroy (update); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } ]]>

Compile the code and run it:

$ gcc -o update update.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./update

On Windows:

C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 update.c C:\> update { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

To verify that the update succeeded, connect with the MongoDB shell.

$ mongo MongoDB shell version: 3.0.6 connecting to: test > use mydb switched to db mydb > db.mycoll.find({"updated" : true}) { "_id" : ObjectId("55ef549236fe322f9490e17b"), "updated" : true, "key" : "new_value" } >
libmongoc-1.3.1/examples/000077500000000000000000000000001264720626300153135ustar00rootroot00000000000000libmongoc-1.3.1/examples/Makefile.am000066400000000000000000000062631264720626300173560ustar00rootroot00000000000000DOC_EXAMPLES = examples/example-client.c EXAMPLE_LDADD = libmongoc-1.0.la if EXPLICIT_LIBS EXAMPLE_LDADD += $(BSON_LIBS) endif EXAMPLE_CFLAGS = \ -I$(top_srcdir)/src/mongoc \ -I$(top_builddir)/src/mongoc \ $(BSON_CFLAGS) noinst_PROGRAMS += example-gridfs example_gridfs_SOURCES = examples/example-gridfs.c example_gridfs_CFLAGS = $(EXAMPLE_CFLAGS) example_gridfs_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += mongoc-dump mongoc_dump_SOURCES = examples/mongoc-dump.c mongoc_dump_CFLAGS = $(EXAMPLE_CFLAGS) mongoc_dump_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += filter-bsondump filter_bsondump_SOURCES = examples/filter-bsondump.c filter_bsondump_CFLAGS = -Wno-deprecated-declarations $(EXAMPLE_CFLAGS) filter_bsondump_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += example-client example_client_SOURCES = examples/example-client.c example_client_CFLAGS = $(EXAMPLE_CFLAGS) example_client_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += example-scram example_scram_SOURCES = examples/example-scram.c example_scram_CFLAGS = $(EXAMPLE_CFLAGS) example_scram_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += mongoc-ping mongoc_ping_SOURCES = examples/mongoc-ping.c mongoc_ping_CFLAGS = $(EXAMPLE_CFLAGS) mongoc_ping_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += mongoc-rpc-validate mongoc_rpc_validate_SOURCES = examples/mongoc-rpc-validate.c mongoc_rpc_validate_CFLAGS = -DMONGOC_COMPILATION $(EXAMPLE_CFLAGS) mongoc_rpc_validate_LDADD = libmongoc-priv.la if EXPLICIT_LIBS mongoc_rpc_validate_LDADD += $(BSON_LIBS) endif noinst_PROGRAMS += mongoc-tail mongoc_tail_SOURCES = examples/mongoc-tail.c mongoc_tail_CFLAGS = $(EXAMPLE_CFLAGS) mongoc_tail_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += find-and-modify find_and_modify_SOURCES = examples/find-and-modify.c find_and_modify_CFLAGS = $(EXAMPLE_CFLAGS) find_and_modify_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += example-matcher example_matcher_SOURCES = examples/example-matcher.c example_matcher_CFLAGS = -Wno-deprecated-declarations $(EXAMPLE_CFLAGS) example_matcher_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += bulk1 bulk1_SOURCES = examples/bulk/bulk1.c bulk1_CFLAGS = $(EXAMPLE_CFLAGS) bulk1_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += bulk2 bulk2_SOURCES = examples/bulk/bulk2.c bulk2_CFLAGS = $(EXAMPLE_CFLAGS) bulk2_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += bulk3 bulk3_SOURCES = examples/bulk/bulk3.c bulk3_CFLAGS = $(EXAMPLE_CFLAGS) bulk3_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += bulk4 bulk4_SOURCES = examples/bulk/bulk4.c bulk4_CFLAGS = $(EXAMPLE_CFLAGS) bulk4_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += bulk5 bulk5_SOURCES = examples/bulk/bulk5.c bulk5_CFLAGS = $(EXAMPLE_CFLAGS) bulk5_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += aggregation1 aggregation1_SOURCES = examples/aggregation/aggregation1.c aggregation1_CFLAGS = $(EXAMPLE_CFLAGS) aggregation1_LDADD = $(EXAMPLE_LDADD) noinst_PROGRAMS += fam fam_SOURCES = examples/find_and_modify_with_opts/fam.c fam_CFLAGS = $(EXAMPLE_CFLAGS) fam_LDADD = $(EXAMPLE_LDADD) EXTRA_DIST += \ examples/find_and_modify_with_opts/bypass.c \ examples/find_and_modify_with_opts/fields.c \ examples/find_and_modify_with_opts/flags.c \ examples/find_and_modify_with_opts/sort.c \ examples/find_and_modify_with_opts/update.c libmongoc-1.3.1/examples/aggregation/000077500000000000000000000000001264720626300176025ustar00rootroot00000000000000libmongoc-1.3.1/examples/aggregation/aggregation1.c000066400000000000000000000023771264720626300223270ustar00rootroot00000000000000#include #include static void print_pipeline (mongoc_collection_t *collection) { mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; bson_t *pipeline; char *str; pipeline = BCON_NEW ("pipeline", "[", "{", "$group", "{", "_id", "$state", "total_pop", "{", "$sum", "$pop", "}", "}", "}", "{", "$match", "{", "total_pop", "{", "$gte", BCON_INT32 (10000000), "}", "}", "}", "]"); cursor = mongoc_collection_aggregate (collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL); while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_json (doc, NULL); printf ("%s\n", str); bson_free (str); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Cursor Failure: %s\n", error.message); } mongoc_cursor_destroy (cursor); bson_destroy (pipeline); } int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_init (); client = mongoc_client_new ("mongodb://localhost:27017"); collection = mongoc_client_get_collection (client, "test", "zipcodes"); print_pipeline (collection); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } libmongoc-1.3.1/examples/bulk/000077500000000000000000000000001264720626300162505ustar00rootroot00000000000000libmongoc-1.3.1/examples/bulk/bulk1.c000066400000000000000000000022371264720626300174360ustar00rootroot00000000000000#include #include #include #include static void bulk1 (mongoc_collection_t *collection) { mongoc_bulk_operation_t *bulk; bson_error_t error; bson_t *doc; bson_t reply; char *str; bool ret; int i; bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); for (i = 0; i < 10000; i++) { doc = BCON_NEW ("i", BCON_INT32 (i)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); } ret = mongoc_bulk_operation_execute (bulk, &reply, &error); str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); if (!ret) { fprintf (stderr, "Error: %s\n", error.message); } bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); } int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_init (); client = mongoc_client_new ("mongodb://localhost/"); collection = mongoc_client_get_collection (client, "test", "test"); bulk1 (collection); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } libmongoc-1.3.1/examples/bulk/bulk2.c000066400000000000000000000040551264720626300174370ustar00rootroot00000000000000#include #include #include #include static void bulk2 (mongoc_collection_t *collection) { mongoc_bulk_operation_t *bulk; bson_error_t error; bson_t *query; bson_t *doc; bson_t reply; char *str; bool ret; int i; bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); /* Remove everything */ query = bson_new (); mongoc_bulk_operation_remove (bulk, query); bson_destroy (query); /* Add a few documents */ for (i = 1; i < 4; i++) { doc = BCON_NEW ("_id", BCON_INT32 (i)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); } /* {_id: 1} => {$set: {foo: "bar"}} */ query = BCON_NEW ("_id", BCON_INT32 (1)); doc = BCON_NEW ("$set", "{", "foo", BCON_UTF8 ("bar"), "}"); mongoc_bulk_operation_update (bulk, query, doc, false); bson_destroy (query); bson_destroy (doc); /* {_id: 4} => {'$inc': {'j': 1}} (upsert) */ query = BCON_NEW ("_id", BCON_INT32 (4)); doc = BCON_NEW ("$inc", "{", "j", BCON_INT32 (1), "}"); mongoc_bulk_operation_update (bulk, query, doc, true); bson_destroy (query); bson_destroy (doc); /* replace {j:1} with {j:2} */ query = BCON_NEW ("j", BCON_INT32 (1)); doc = BCON_NEW ("j", BCON_INT32 (2)); mongoc_bulk_operation_replace_one (bulk, query, doc, false); bson_destroy (query); bson_destroy (doc); ret = mongoc_bulk_operation_execute (bulk, &reply, &error); str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); if (!ret) { printf ("Error: %s\n", error.message); } bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); } int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_init (); client = mongoc_client_new ("mongodb://localhost/"); collection = mongoc_client_get_collection (client, "test", "test"); bulk2 (collection); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } libmongoc-1.3.1/examples/bulk/bulk3.c000066400000000000000000000032621264720626300174370ustar00rootroot00000000000000#include #include #include #include static void bulk3 (mongoc_collection_t *collection) { mongoc_bulk_operation_t *bulk; bson_error_t error; bson_t *query; bson_t *doc; bson_t reply; char *str; bool ret; /* false indicates unordered */ bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); /* Add a document */ doc = BCON_NEW ("_id", BCON_INT32 (1)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); /* remove {_id: 2} */ query = BCON_NEW ("_id", BCON_INT32 (2)); mongoc_bulk_operation_remove_one (bulk, query); bson_destroy (query); /* insert {_id: 3} */ doc = BCON_NEW ("_id", BCON_INT32 (3)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); /* replace {_id:4} {'i': 1} */ query = BCON_NEW ("_id", BCON_INT32 (4)); doc = BCON_NEW ("i", BCON_INT32 (1)); mongoc_bulk_operation_replace_one (bulk, query, doc, false); bson_destroy (query); bson_destroy (doc); ret = mongoc_bulk_operation_execute (bulk, &reply, &error); str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); if (!ret) { printf ("Error: %s\n", error.message); } bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); } int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_init (); client = mongoc_client_new ("mongodb://localhost/"); collection = mongoc_client_get_collection (client, "test", "test"); bulk3 (collection); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } libmongoc-1.3.1/examples/bulk/bulk4.c000066400000000000000000000026721264720626300174440ustar00rootroot00000000000000#include #include #include #include static void bulk4 (mongoc_collection_t *collection) { mongoc_write_concern_t *wc; mongoc_bulk_operation_t *bulk; bson_error_t error; bson_t *doc; bson_t reply; char *str; bool ret; wc = mongoc_write_concern_new (); mongoc_write_concern_set_w (wc, 4); mongoc_write_concern_set_wtimeout (wc, 100); /* milliseconds */ bulk = mongoc_collection_create_bulk_operation (collection, true, wc); /* Two inserts */ doc = BCON_NEW ("_id", BCON_INT32 (10)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); doc = BCON_NEW ("_id", BCON_INT32 (11)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); ret = mongoc_bulk_operation_execute (bulk, &reply, &error); str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); if (!ret) { printf ("Error: %s\n", error.message); } bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_write_concern_destroy (wc); } int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_init (); client = mongoc_client_new ("mongodb://localhost/"); collection = mongoc_client_get_collection (client, "test", "test"); bulk4 (collection); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } libmongoc-1.3.1/examples/bulk/bulk5.c000066400000000000000000000056341264720626300174460ustar00rootroot00000000000000#include #include #include #include static void bulk5_fail (mongoc_collection_t *collection) { mongoc_bulk_operation_t *bulk; bson_error_t error; bson_t *doc; bson_t reply; char *str; bool ret; bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); /* Two inserts */ doc = BCON_NEW ("_id", BCON_INT32 (31)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); doc = BCON_NEW ("_id", BCON_INT32 (32)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); /* The above documents do not comply to the schema validation rules * we created previously, so this will result in an error */ ret = mongoc_bulk_operation_execute (bulk, &reply, &error); str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); if (!ret) { printf ("Error: %s\n", error.message); } bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); } static void bulk5_success (mongoc_collection_t *collection) { mongoc_bulk_operation_t *bulk; bson_error_t error; bson_t *doc; bson_t reply; char *str; bool ret; bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); /* Allow this document to bypass document validation. * NOTE: When authentication is enabled, the authenticated user must have * either the "dbadmin" or "restore" roles to bypass document validation */ mongoc_bulk_operation_set_bypass_document_validation (bulk, true); /* Two inserts */ doc = BCON_NEW ("_id", BCON_INT32 (31)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); doc = BCON_NEW ("_id", BCON_INT32 (32)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); ret = mongoc_bulk_operation_execute (bulk, &reply, &error); str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); if (!ret) { printf ("Error: %s\n", error.message); } bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); } int main (int argc, char *argv[]) { bson_t *options; bson_error_t error; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_database_t *database; mongoc_init (); client = mongoc_client_new ("mongodb://localhost/"); database = mongoc_client_get_database (client, "testasdf"); /* Create schema validator */ options = BCON_NEW ("validator", "{", "number", "{", "$gte", BCON_INT32 (5), "}", "}"); collection = mongoc_database_create_collection (database, "collname", options, &error); if (collection) { bulk5_fail (collection); bulk5_success (collection); mongoc_collection_destroy (collection); } else { fprintf(stderr, "Couldn't create collection: '%s'\n", error.message); } bson_free (options); mongoc_database_destroy (database); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } libmongoc-1.3.1/examples/example-client.c000066400000000000000000000034621264720626300203730ustar00rootroot00000000000000/* gcc example.c -o example $(pkg-config --cflags --libs libmongoc-1.0) */ /* ./example-client [CONNECTION_STRING [COLLECTION_NAME]] */ #include #include #include int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; const char *uristr = "mongodb://127.0.0.1/"; const char *collection_name = "test"; bson_t query; char *str; mongoc_init (); if (argc > 1) { uristr = argv [1]; } if (argc > 2) { collection_name = argv [2]; } client = mongoc_client_new (uristr); if (!client) { fprintf (stderr, "Failed to parse URI.\n"); return EXIT_FAILURE; } bson_init (&query); #if 0 bson_append_utf8 (&query, "hello", -1, "world", -1); #endif collection = mongoc_client_get_collection (client, "test", collection_name); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, /* Fields, NULL for all. */ NULL); /* Read Prefs, NULL for default */ while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_json (doc, NULL); fprintf (stdout, "%s\n", str); bson_free (str); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Cursor Failure: %s\n", error.message); return EXIT_FAILURE; } bson_destroy (&query); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return EXIT_SUCCESS; } libmongoc-1.3.1/examples/example-gridfs.c000066400000000000000000000057571264720626300204040ustar00rootroot00000000000000#include #include #include #include int main (int argc, char *argv[]) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_gridfs_file_list_t *list; mongoc_gridfs_file_opt_t opt = { 0 }; mongoc_client_t *client; mongoc_stream_t *stream; bson_t query; bson_t child; bson_error_t error; ssize_t r; char buf[4096]; mongoc_iovec_t iov; const char * filename; const char * command; if (argc < 2) { fprintf(stderr, "usage - %s command ...\n", argv[0]); return 1; } mongoc_init(); iov.iov_base = (void *)buf; iov.iov_len = sizeof buf; /* connect to localhost client */ client = mongoc_client_new ("mongodb://127.0.0.1:27017"); assert(client); /* grab a gridfs handle in test prefixed by fs */ gridfs = mongoc_client_get_gridfs (client, "test", "fs", &error); assert(gridfs); command = argv[1]; filename = argv[2]; if (strcmp(command, "read") == 0) { if (argc != 3) { fprintf(stderr, "usage - %s read filename\n", argv[0]); return 1; } file = mongoc_gridfs_find_one_by_filename(gridfs, filename, &error); assert(file); stream = mongoc_stream_gridfs_new (file); assert(stream); for (;;) { r = mongoc_stream_readv (stream, &iov, 1, -1, 0); assert (r >= 0); if (r == 0) { break; } if (fwrite (iov.iov_base, 1, r, stdout) != r) { MONGOC_ERROR ("Failed to write to stdout. Exiting.\n"); exit (1); } } mongoc_stream_destroy (stream); mongoc_gridfs_file_destroy (file); } else if (strcmp(command, "list") == 0) { bson_init (&query); bson_append_document_begin (&query, "$orderby", -1, &child); bson_append_int32 (&child, "filename", -1, 1); bson_append_document_end (&query, &child); bson_append_document_begin (&query, "$query", -1, &child); bson_append_document_end (&query, &child); list = mongoc_gridfs_find (gridfs, &query); bson_destroy (&query); while ((file = mongoc_gridfs_file_list_next (list))) { const char * name = mongoc_gridfs_file_get_filename(file); printf("%s\n", name ? name : "?"); mongoc_gridfs_file_destroy (file); } mongoc_gridfs_file_list_destroy (list); } else if (strcmp(command, "write") == 0) { if (argc != 4) { fprintf(stderr, "usage - %s write filename input_file\n", argv[0]); return 1; } stream = mongoc_stream_file_new_for_path (argv [3], O_RDONLY, 0); assert (stream); opt.filename = filename; file = mongoc_gridfs_create_file_from_stream (gridfs, stream, &opt); assert(file); mongoc_gridfs_file_save(file); mongoc_gridfs_file_destroy(file); } else { fprintf(stderr, "Unknown command"); return 1; } mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } libmongoc-1.3.1/examples/example-matcher.c000066400000000000000000000032101264720626300205270ustar00rootroot00000000000000#include #include #include static void log_query (const bson_t *doc, const bson_t *query) { char *str1; char *str2; str1 = bson_as_json (doc, NULL); str2 = bson_as_json (query, NULL); printf ("Matching %s against %s\n", str2, str1); bson_free (str1); bson_free (str2); } static void check_match (const bson_t *doc, const bson_t *query) { bson_error_t error; mongoc_matcher_t *matcher = mongoc_matcher_new (query, &error); if (!matcher) { fprintf (stderr, "Error: %s\n", error.message); return; } if (mongoc_matcher_match (matcher, doc)) { printf (" Document matched!\n"); } else { printf (" No match.\n"); } mongoc_matcher_destroy (matcher); } static void example (void) { bson_t *query; bson_t *doc; doc = BCON_NEW ("hello", "[", "{", "foo", BCON_UTF8 ("bar"), "}", "]"); query = BCON_NEW ("hello.0.foo", BCON_UTF8 ("bar")); log_query (doc, query); check_match (doc, query); bson_destroy (doc); bson_destroy (query); /* i is > 1 or i < -1. */ query = BCON_NEW ("$or", "[", "{", "i", "{", "$gt", BCON_INT32 (1), "}", "}", "{", "i", "{", "$lt", BCON_INT32 (-1), "}", "}", "]"); doc = BCON_NEW ("i", BCON_INT32 (2)); log_query (doc, query); check_match (doc, query); bson_destroy (doc); doc = BCON_NEW ("i", BCON_INT32 (0)); log_query (doc, query); check_match (doc, query); bson_destroy (doc); bson_destroy (query); } int main (int argc, char *argv[]) { mongoc_init (); example (); mongoc_cleanup (); return 0; } libmongoc-1.3.1/examples/example-scram.c000066400000000000000000000046401264720626300202210ustar00rootroot00000000000000/* gcc example.c -o example $(pkg-config --cflags --libs libmongoc-1.0) */ /* ./example-scram */ #include #include #include int main (int argc, char *argv[]) { mongoc_client_t *client = NULL; mongoc_database_t *database = NULL; mongoc_collection_t *collection = NULL; mongoc_cursor_t *cursor = NULL; bson_error_t error; const char *uristr = "mongodb://127.0.0.1/"; const char *authuristr; bson_t roles; bson_t query; const bson_t *doc; if (argc != 2) { printf("%s - [implicit|scram|cr]\n", argv[0]); return 1; } if (strcmp(argv[1], "implicit") == 0) { authuristr = "mongodb://user,=:pass@127.0.0.1/test"; } else if (strcmp(argv[1], "scram") == 0) { authuristr = "mongodb://user,=:pass@127.0.0.1/test?authMechanism=SCRAM-SHA-1"; } else if (strcmp(argv[1], "cr") == 0) { authuristr = "mongodb://user,=:pass@127.0.0.1/test?authMechanism=MONGODB-CR"; } else { printf("%s - [implicit|scram|cr]\n", argv[0]); return 1; } mongoc_init (); bson_init (&roles); bson_init (&query); client = mongoc_client_new (uristr); if (!client) { fprintf (stderr, "Failed to parse URI.\n"); goto CLEANUP; } database = mongoc_client_get_database (client, "test"); BCON_APPEND (&roles, "0", "{", "role", "root", "db", "admin", "}"); mongoc_database_add_user (database, "user,=", "pass", &roles, NULL, &error); mongoc_database_destroy (database); database = NULL; mongoc_client_destroy (client); client = NULL; client = mongoc_client_new (authuristr); if (!client) { fprintf (stderr, "failed to parse SCRAM uri\n"); goto CLEANUP; } collection = mongoc_client_get_collection (client, "test", "test"); cursor = mongoc_collection_find (collection, (mongoc_query_flags_t)0, 0, 0, 0, &query, NULL, NULL); mongoc_cursor_next (cursor, &doc); if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Auth error: %s\n", error.message); goto CLEANUP; } CLEANUP: bson_destroy (&roles); bson_destroy (&query); if (collection) { mongoc_collection_destroy (collection); } if (database) { mongoc_database_destroy (database); } if (client) { mongoc_client_destroy (client); } if (cursor) { mongoc_cursor_destroy (cursor); } mongoc_cleanup (); return EXIT_SUCCESS; } libmongoc-1.3.1/examples/filter-bsondump.c000066400000000000000000000027441264720626300206000ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include /* * This is an example that reads BSON documents from STDIN and prints them * to standard output as JSON if they match {'hello': 'world'}. */ int main (int argc, char *argv[]) { mongoc_matcher_t *matcher; bson_reader_t *reader; const bson_t *bson; bson_t *spec; char *str; int fd; mongoc_init (); #ifdef _WIN32 fd = fileno (stdin); #else fd = STDIN_FILENO; #endif reader = bson_reader_new_from_fd (fd, false); spec = BCON_NEW ("hello", "world"); matcher = mongoc_matcher_new (spec, NULL); while ((bson = bson_reader_read (reader, NULL))) { if (mongoc_matcher_match (matcher, bson)) { str = bson_as_json (bson, NULL); printf ("%s\n", str); bson_free (str); } } bson_reader_destroy (reader); bson_destroy (spec); return 0; } libmongoc-1.3.1/examples/find-and-modify.c000066400000000000000000000023521264720626300204260ustar00rootroot00000000000000#include #include #include int main (int argc, char *argv[]) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; bson_t *query; bson_t *update; bson_t reply; char *str; mongoc_init (); client = mongoc_client_new ("mongodb://127.0.0.1:27017/"); collection = mongoc_client_get_collection (client, "test", "test"); /* * Build our query, {"cmpxchg": 1} */ query = BCON_NEW ("cmpxchg", BCON_INT32 (1)); /* * Build our update. {"$set": {"cmpxchg": 2}} */ update = BCON_NEW ("$set", "{", "cmpxchg", BCON_INT32 (2), "}"); /* * Submit the findAndModify. */ if (!mongoc_collection_find_and_modify (collection, query, NULL, update, NULL, false, false, true, &reply, &error)) { fprintf (stderr, "find_and_modify() failure: %s\n", error.message); return 1; } /* * Print the result as JSON. */ str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); /* * Cleanup. */ bson_destroy (query); bson_destroy (update); bson_destroy (&reply); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return 0; } libmongoc-1.3.1/examples/find_and_modify_with_opts/000077500000000000000000000000001264720626300225245ustar00rootroot00000000000000libmongoc-1.3.1/examples/find_and_modify_with_opts/bypass.c000066400000000000000000000023021264720626300241660ustar00rootroot00000000000000void fam_bypass(mongoc_collection_t *collection) { mongoc_find_and_modify_opts_t *opts; bson_t reply; bson_t *update; bson_error_t error; bson_t query = BSON_INITIALIZER; bool success; /* Find Zlatan Ibrahimovic, the striker */ BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); BSON_APPEND_UTF8 (&query, "profession", "Football player"); /* Bump his age */ update = BCON_NEW ("$inc", "{", "age", BCON_INT32 (1), "}"); opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_update (opts, update); /* He can still play, even though he is pretty old. */ mongoc_find_and_modify_opts_set_bypass_document_validation (opts, true); success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); if (success) { char *str; str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); } else { fprintf(stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); } bson_destroy (&reply); bson_destroy (update); bson_destroy (&query); mongoc_find_and_modify_opts_destroy (opts); } libmongoc-1.3.1/examples/find_and_modify_with_opts/fam.c000066400000000000000000000022241264720626300234330ustar00rootroot00000000000000#include #include #include "flags.c" #include "bypass.c" #include "update.c" #include "fields.c" #include "sort.c" int main(void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; bson_error_t error; bson_t *options; client = mongoc_client_new ("mongodb://localhost:27017/admin"); database = mongoc_client_get_database (client, "databaseName"); options = BCON_NEW ( "validator", "{", "age", "{", "$lte", BCON_INT32 (34), "}", "}", "validationAction", BCON_UTF8 ("error"), "validationLevel", BCON_UTF8 ("moderate")); collection = mongoc_database_create_collection (database, "collectionName", options, &error); if (!collection) { fprintf(stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); return 1; } fam_flags (collection); fam_bypass (collection); fam_update (collection); fam_fields (collection); fam_sort (collection); mongoc_collection_drop (collection, NULL); bson_destroy (options); mongoc_database_destroy (database); mongoc_collection_destroy (collection); mongoc_client_destroy (client); return 0; } libmongoc-1.3.1/examples/find_and_modify_with_opts/fields.c000066400000000000000000000024621264720626300241420ustar00rootroot00000000000000void fam_fields(mongoc_collection_t *collection) { mongoc_find_and_modify_opts_t *opts; bson_t fields = BSON_INITIALIZER; bson_t *update; bson_t reply; bson_error_t error; bson_t query = BSON_INITIALIZER; bool success; /* Find Zlatan Ibrahimovic */ BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); /* Return his goal tally */ BSON_APPEND_INT32 (&fields, "goals", 1); /* Bump his goal tally */ update = BCON_NEW ("$inc", "{", "goals", BCON_INT32 (1), "}"); opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_update (opts, update); mongoc_find_and_modify_opts_set_fields (opts, &fields); /* Return the new tally */ mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_RETURN_NEW); success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); if (success) { char *str; str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); } else { fprintf(stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); } bson_destroy (&reply); bson_destroy (update); bson_destroy (&fields); bson_destroy (&query); mongoc_find_and_modify_opts_destroy (opts); } libmongoc-1.3.1/examples/find_and_modify_with_opts/flags.c000066400000000000000000000026171264720626300237720ustar00rootroot00000000000000void fam_flags(mongoc_collection_t *collection) { mongoc_find_and_modify_opts_t *opts; bson_t reply; bson_error_t error; bson_t query = BSON_INITIALIZER; bson_t *update; bool success; /* Find Zlatan Ibrahimovic, the striker */ BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); BSON_APPEND_UTF8 (&query, "profession", "Football player"); BSON_APPEND_INT32 (&query, "age", 34); BSON_APPEND_INT32 (&query, "goals", (16+35+23+57+16+14+28+84)+(1+6+62)); /* Add his football position */ update = BCON_NEW ("$set", "{", "position", BCON_UTF8 ("striker"), "}"); opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_update (opts, update); /* Create the document if it didn't exist, and return the updated document */ mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_UPSERT|MONGOC_FIND_AND_MODIFY_RETURN_NEW); success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); if (success) { char *str; str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); } else { fprintf(stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); } bson_destroy (&reply); bson_destroy (update); bson_destroy (&query); mongoc_find_and_modify_opts_destroy (opts); } libmongoc-1.3.1/examples/find_and_modify_with_opts/sort.c000066400000000000000000000022311264720626300236550ustar00rootroot00000000000000void fam_sort(mongoc_collection_t *collection) { mongoc_find_and_modify_opts_t *opts; bson_t *update; bson_t sort = BSON_INITIALIZER; bson_t reply; bson_error_t error; bson_t query = BSON_INITIALIZER; bool success; /* Find all users with the lastname Ibrahimovic */ BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); /* Sort by age (descending) */ BSON_APPEND_INT32 (&sort, "age", -1); /* Bump his goal tally */ update = BCON_NEW ("$set", "{", "oldest", BCON_BOOL (true), "}"); opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_update (opts, update); mongoc_find_and_modify_opts_set_sort (opts, &sort); success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); if (success) { char *str; str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); } else { fprintf(stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); } bson_destroy (&reply); bson_destroy (update); bson_destroy (&sort); bson_destroy (&query); mongoc_find_and_modify_opts_destroy (opts); } libmongoc-1.3.1/examples/find_and_modify_with_opts/update.c000066400000000000000000000023321264720626300241520ustar00rootroot00000000000000void fam_update(mongoc_collection_t *collection) { mongoc_find_and_modify_opts_t *opts; bson_t *update; bson_t reply; bson_error_t error; bson_t query = BSON_INITIALIZER; bool success; /* Find Zlatan Ibrahimovic */ BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); /* Make him a book author */ update = BCON_NEW ("$set", "{", "author", BCON_BOOL (true), "}"); opts = mongoc_find_and_modify_opts_new (); /* Note that the document returned is the _previous_ version of the document * To fetch the modified new version, use * mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_RETURN_NEW); */ mongoc_find_and_modify_opts_set_update (opts, update); success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); if (success) { char *str; str = bson_as_json (&reply, NULL); printf ("%s\n", str); bson_free (str); } else { fprintf(stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); } bson_destroy (&reply); bson_destroy (update); bson_destroy (&query); mongoc_find_and_modify_opts_destroy (opts); } libmongoc-1.3.1/examples/mongoc-dump.c000066400000000000000000000143431264720626300177110ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include static bool mongoc_dump_mkdir_p (const char *path, int mode) { #ifdef _WIN32 if (0 != _access (path, 0)) { if (0 != _mkdir (path)) { return false; } } #else if (0 != access (path, F_OK)) { if (0 != mkdir (path, mode)) { return false; } } #endif return true; } static int mongoc_dump_collection (mongoc_client_t *client, const char *database, const char *collection) { mongoc_collection_t *col; mongoc_cursor_t *cursor; const bson_t *doc; bson_error_t error; bson_t query = BSON_INITIALIZER; FILE *stream; char *path; int ret = EXIT_SUCCESS; path = bson_strdup_printf ("dump/%s/%s.bson", database, collection); #ifdef _WIN32 if (0 == _access (path, 0)) { _unlink (path); } #else if (0 == access (path, F_OK)) { unlink (path); } #endif stream = fopen (path, "w"); if (!stream) { fprintf (stderr, "Failed to open \"%s\", aborting.\n", path); exit (EXIT_FAILURE); } col = mongoc_client_get_collection (client, database, collection); cursor = mongoc_collection_find (col, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, NULL); while (mongoc_cursor_next (cursor, &doc)) { if (BSON_UNLIKELY (doc->len != fwrite (bson_get_data (doc), 1, doc->len, stream))) { fprintf (stderr, "Failed to write %u bytes to %s\n", doc->len, path); ret = EXIT_FAILURE; goto cleanup; } } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "ERROR: %s\n", error.message); ret = EXIT_FAILURE; } cleanup: bson_free (path); fclose (stream); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (col); return ret; } static int mongoc_dump_database (mongoc_client_t *client, const char *database, const char *collection) { mongoc_database_t *db; bson_error_t error; char *path; char **str; int ret = EXIT_SUCCESS; int i; BSON_ASSERT (database); path = bson_strdup_printf ("dump/%s", database); if (!mongoc_dump_mkdir_p (path, 0750)) { fprintf (stderr, "failed to create directory \"%s\"", path); bson_free (path); return EXIT_FAILURE; } bson_free (path); if (collection) { return mongoc_dump_collection (client, database, collection); } db = mongoc_client_get_database (client, database); str = mongoc_database_get_collection_names (db, &error); for (i = 0; str [i]; i++) { if (EXIT_SUCCESS != mongoc_dump_collection (client, database, str [i])) { ret = EXIT_FAILURE; goto cleanup; } } cleanup: mongoc_database_destroy (db); bson_strfreev (str); return ret; } static int mongoc_dump (mongoc_client_t *client, const char *database, const char *collection) { bson_error_t error; char **str; int i; if (!mongoc_dump_mkdir_p ("dump", 0750)) { perror ("Failed to create directory \"dump\""); return EXIT_FAILURE; } if (database) { return mongoc_dump_database (client, database, collection); } if (!(str = mongoc_client_get_database_names (client, &error))) { fprintf (stderr, "Failed to fetch database names: %s\n", error.message); return EXIT_FAILURE; } for (i = 0; str [i]; i++) { if (EXIT_SUCCESS != mongoc_dump_database (client, str [i], NULL)) { bson_strfreev (str); return EXIT_FAILURE; } } bson_strfreev (str); return EXIT_SUCCESS; } static void usage (FILE *stream) { fprintf (stream, "Usage: mongoc-dump [OPTIONS]\n" "\n" "Options:\n" "\n" " -h HOST Optional hostname to connect to [127.0.0.1].\n" " -p PORT Optional port to connect to [27017].\n" " -d DBNAME Optional database name to dump.\n" " -c COLNAME Optional collection name to dump.\n" " --ssl Use SSL when connecting to server.\n" "\n"); } int main (int argc, char *argv[]) { mongoc_client_t *client; const char *collection = NULL; const char *database = NULL; const char *host = "127.0.0.1"; uint16_t port = 27017; bool ssl = false; char *uri; int ret; int i; mongoc_init (); for (i = 1; i < argc; i++) { if (0 == strcmp (argv [i], "-c") && ((i + 1) < argc)) { collection = argv [++i]; } else if (0 == strcmp (argv [i], "-d") && ((i + 1) < argc)) { database = argv [++i]; } else if (0 == strcmp (argv [i], "--help")) { usage (stdout); return EXIT_SUCCESS; } else if (0 == strcmp (argv [i], "-h") && ((i + 1) < argc)) { host = argv [++i]; } else if (0 == strcmp (argv [i], "--ssl")) { ssl = true; } else if (0 == strcmp (argv [i], "-p") && ((i + 1) < argc)) { port = atoi (argv [++i]); if (!port) { fprintf (stderr, "Invalid port \"%s\"", argv [i]); return EXIT_FAILURE; } } else { fprintf (stderr, "Unknown argument \"%s\"\n", argv [i]); return EXIT_FAILURE; } } uri = bson_strdup_printf ("mongodb://%s:%hu/%s?ssl=%s", host, port, database ? database : "", ssl ? "true" : "false"); if (!(client = mongoc_client_new (uri))) { fprintf (stderr, "Invalid connection URI: %s\n", uri); return EXIT_FAILURE; } ret = mongoc_dump (client, database, collection); mongoc_client_destroy (client); return ret; } libmongoc-1.3.1/examples/mongoc-ping.c000066400000000000000000000040211264720626300176710ustar00rootroot00000000000000/* * Copyright 2013-2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include int main (int argc, char *argv[]) { mongoc_database_t *database; mongoc_cursor_t *cursor; mongoc_client_t *client; const bson_t *reply; uint16_t port; bson_error_t error; bson_t ping; char *host_and_port; char *str; if (argc < 2 || argc > 3) { fprintf(stderr, "usage: %s HOSTNAME [PORT]\n", argv[0]); return 1; } mongoc_init(); port = (argc == 3) ? atoi(argv[2]) : 27017; if (strncmp (argv[1], "mongodb://", 10) == 0) { host_and_port = bson_strdup (argv [1]); } else { host_and_port = bson_strdup_printf("mongodb://%s:%hu", argv[1], port); } client = mongoc_client_new(host_and_port); if (!client) { fprintf(stderr, "Invalid hostname or port: %s\n", host_and_port); return 2; } bson_init(&ping); bson_append_int32(&ping, "ping", 4, 1); database = mongoc_client_get_database(client, "test"); cursor = mongoc_database_command(database, (mongoc_query_flags_t)0, 0, 1, 0, &ping, NULL, NULL); if (mongoc_cursor_next(cursor, &reply)) { str = bson_as_json(reply, NULL); fprintf(stdout, "%s\n", str); bson_free(str); } else if (mongoc_cursor_error(cursor, &error)) { fprintf(stderr, "Ping failure: %s\n", error.message); return 3; } mongoc_cursor_destroy(cursor); bson_destroy(&ping); mongoc_client_destroy(client); bson_free(host_and_port); return 0; } libmongoc-1.3.1/examples/mongoc-rpc-validate.c000066400000000000000000000053761264720626300213250ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * This example can only be used internally to the library as it uses * private features that are not exported in the public ABI. It does, * however, illustrate some of the internals of the system. */ #include #include #include #include #include #include #include #include static void validate (const char *name) /* IN */ { mongoc_stream_t *stream; mongoc_rpc_t rpc; #ifdef _WIN32 struct _stat st; #else struct stat st; #endif uint8_t *buf; int32_t len; int ret; stream = mongoc_stream_file_new_for_path (name, O_RDONLY, 0); if (!stream) { perror ("failed to open file"); exit (EXIT_FAILURE); } #ifdef _WIN32 ret = _stat (name, &st); #else ret = stat (name, &st); #endif if (ret != 0) { perror ("failed to stat() file."); exit (EXIT_FAILURE); } if ((st.st_size > (100 * 1024 * 1024)) || (st.st_size < 16)) { fprintf (stderr, "%s: unreasonable message size\n", name); exit (EXIT_FAILURE); } buf = (uint8_t *)bson_malloc (st.st_size); if (buf == NULL) { fprintf (stderr, "%s: Failed to malloc %d bytes.\n", name, (int)st.st_size); exit (EXIT_FAILURE); } if (st.st_size != mongoc_stream_read (stream, buf, st.st_size, st.st_size, -1)) { fprintf (stderr, "%s: Failed to read %d bytes into buffer.\n", name, (int)st.st_size); exit (EXIT_FAILURE); } memcpy (&len, buf, 4); len = BSON_UINT32_FROM_LE (len); if (len != st.st_size) { fprintf (stderr, "%s is invalid. Invalid Length.\n", name); exit (EXIT_FAILURE); } if (!_mongoc_rpc_scatter (&rpc, buf, st.st_size)) { fprintf (stderr, "%s is invalid. Invalid Format.\n", name); exit (EXIT_FAILURE); } fprintf (stdout, "%s is valid.\n", name); bson_free (buf); } int main (int argc, char *argv[]) { int i; if (argc < 2) { fprintf (stderr, "usage: %s FILE...\n", argv[0]); return EXIT_FAILURE; } mongoc_init (); for (i = 1; i < argc; i++) { validate (argv [i]); } return EXIT_SUCCESS; } libmongoc-1.3.1/examples/mongoc-tail.c000066400000000000000000000053511264720626300176740ustar00rootroot00000000000000#include #include #include #include #ifdef _WIN32 #define sleep(_n) Sleep((_n) * 1000) #endif static void print_bson (const bson_t *b) { char *str; str = bson_as_json(b, NULL); fprintf(stdout, "%s\n", str); bson_free(str); } static mongoc_cursor_t * query_collection (mongoc_collection_t *collection, uint32_t last_time) { mongoc_cursor_t *cursor; bson_t query; bson_t gt; int fflags = (MONGOC_QUERY_TAILABLE_CURSOR | MONGOC_QUERY_AWAIT_DATA | MONGOC_QUERY_SLAVE_OK); BSON_ASSERT(collection); bson_init(&query); bson_append_document_begin(&query, "ts", 2, >); bson_append_timestamp(>, "$gt", 3, last_time, 0); bson_append_document_end(&query, >); cursor = mongoc_collection_find(collection, (mongoc_query_flags_t)fflags, 0, 0, 0, &query, NULL, NULL); bson_destroy(&query); return cursor; } static void tail_collection (mongoc_collection_t *collection) { mongoc_cursor_t *cursor; uint32_t last_time; const bson_t *doc; bson_error_t error; bson_iter_t iter; BSON_ASSERT(collection); last_time = (uint32_t)time(NULL); while (true) { cursor = query_collection(collection, last_time); while (!mongoc_cursor_error(cursor, &error) && mongoc_cursor_more(cursor)) { if (mongoc_cursor_next(cursor, &doc)) { if (bson_iter_init_find(&iter, doc, "ts") && BSON_ITER_HOLDS_TIMESTAMP(&iter)) { bson_iter_timestamp(&iter, &last_time, NULL); } print_bson(doc); } } if (mongoc_cursor_error(cursor, &error)) { if ((error.domain == MONGOC_ERROR_QUERY) && (error.code == MONGOC_ERROR_QUERY_NOT_TAILABLE)) { fprintf(stderr, "%s\n", error.message); exit(1); } } mongoc_cursor_destroy(cursor); sleep(1); } } int main (int argc, char *argv[]) { mongoc_collection_t *collection; mongoc_client_t *client; if (argc != 2) { fprintf(stderr, "usage: %s MONGO_URI\n", argv[0]); return EXIT_FAILURE; } mongoc_init(); client = mongoc_client_new(argv[1]); if (!client) { fprintf(stderr, "Invalid URI: \"%s\"\n", argv[1]); return EXIT_FAILURE; } collection = mongoc_client_get_collection(client, "local", "oplog.rs"); tail_collection(collection); mongoc_collection_destroy(collection); mongoc_client_destroy(client); return 0; } libmongoc-1.3.1/orchestration_configs/000077500000000000000000000000001264720626300200715ustar00rootroot00000000000000libmongoc-1.3.1/orchestration_configs/certificates/000077500000000000000000000000001264720626300225365ustar00rootroot00000000000000libmongoc-1.3.1/orchestration_configs/certificates/ca.pem000066400000000000000000000055631264720626300236350ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDczCCAlugAwIBAgIBATANBgkqhkiG9w0BAQUFADB0MRcwFQYDVQQDEw5LZXJu ZWwgVGVzdCBDQTEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RCMRYw FAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkGA1UE BhMCVVMwHhcNMTQwNzE3MTYwMDAwWhcNMjAwNzE3MTYwMDAwWjB0MRcwFQYDVQQD Ew5LZXJuZWwgVGVzdCBDQTEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25n b0RCMRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazEL MAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCBxSXj qA5y2EMQkcmvLDNikE88Og3+spJ3ex60HWVPk8EeXN68jyfbKLYsoCcBE2rBAE/N shVBJa8irh0o/UTh1XNW4iGCsfMvYamXiHnaOjmGVKjfBoj6pzQH0uK0X5olm3Sa zZPkLLCR81yxsK6woJZMFTvrlEjxj/SmDZ9tVXW692bC4i6nGvOCSpgv9kms85xO Ed2xbuCLXFDXKafXZd5AK+iegkDs3ah7VXMEE8sbqGnlqC1nsy5bpCnb7aC+3af7 SV2XEFlSQT5kwTmk9CvTDzM9O78SO8nNhEOFBLQEdGDGd3BShE8dCdh2JTy3zKsb WeE+mxy0mEwxNfGfAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF BQADggEBAANwbvhM5K/Jcl6yzUSqAawvyAypT5aWBob7rt9KFq/aemjMN0gY2nsS 8WTGd9jiXlxGc/TzrK6MOsJ904UAFE1L9uR//G1gIBa9dNbYoiii2Fc8b1xDVJEP b23rl/+GAT6UTSY+YgEjeA4Jk6H9zotO07lSw06rbCQam5SdA5UiMvuLHWCo3BHY 8WzqLiW/uHlb4K5prF9yuTUBEIgkRvvvyOKXlRvm1Ed5UopT2hmwA86mffAfgJc2 vSbm9/8Q00fYwO7mluB6mbEcnbquaqRLoB83k+WbwUAZ2yjWHXuXVMPwyaysazcp nOjaLwQJQgKejY62PiNcw7xC/nIxBeI= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAgcUl46gOcthDEJHJrywzYpBPPDoN/rKSd3setB1lT5PBHlze vI8n2yi2LKAnARNqwQBPzbIVQSWvIq4dKP1E4dVzVuIhgrHzL2Gpl4h52jo5hlSo 3waI+qc0B9LitF+aJZt0ms2T5CywkfNcsbCusKCWTBU765RI8Y/0pg2fbVV1uvdm wuIupxrzgkqYL/ZJrPOcThHdsW7gi1xQ1ymn12XeQCvonoJA7N2oe1VzBBPLG6hp 5agtZ7MuW6Qp2+2gvt2n+0ldlxBZUkE+ZME5pPQr0w8zPTu/EjvJzYRDhQS0BHRg xndwUoRPHQnYdiU8t8yrG1nhPpsctJhMMTXxnwIDAQABAoIBAD5iGOnM800wO2Uu wGbOd9FNEFoiinHDRHfdnw/1BavwmqjO+mBo7T8E3jarsrRosiwfyz1V+7O6uuuQ CgKXZlKuOuksgfGDPCWt7EolWHaZAOhbsGaujJD6ah/MuCD/yGmFxtNYOl05QpSX Cht9lSzhtf7TQl/og/xkOLbO27JB540ck/OCSOczXg9Z/O8AmIUyDn7AKb6G1Zhk 2IN//HQoAvDUMZLWrzy+L7YGbA8pBR3yiPsYBH0rX2Oc9INpiGA+B9Nf1HDDsxeZ /o+5xLbRDDfIDtlYO0cekJ053W0zUQLrMEIn9991EpG2O/fPgs10NlKJtaFH8CmT ExgVA9ECgYEA+6AjtUdxZ0BL3Wk773nmhesNH5/5unWFaGgWpMEaEM7Ou7i6QApL KAbzOYItV3NNCbkcrejq7jsDGEmiwUOdXeQx6XN7/Gb2Byc/wezy5ALi0kcUwaur 6s9+Ah+T4vcU2AjfuCWXIpe46KLEbwORmCRQGwkCBCwRhHGt5sGGxTkCgYEAhAaw voHI6Cb+4z3PNAKRnf2rExBYRyCz1KF16ksuwJyQSLzFleXRyRWFUEwLuVRL0+EZ JXhMbtrILrc23dJGEsB8kOCFehSH/IuL5eB0QfKpDFA+e6pimsbVeggx/rZhcERB WkcV3jN4O82gSL3EnIgvAT1/nwhmbmjvDhFJhZcCgYBaW4E3IbaZaz9S/O0m69Fa GbQWvS3CRV1oxqgK9cTUcE9Qnd9UC949O3GwHw0FMERjz3N7B/8FGW/dEuQ9Hniu NLmvqWbGlnqWywNcMihutJKbDCdp/Km5olUPkiNbB3sWsOkViXoiU/V0pK6BZvir d67EZpGwydpogyH9kVVCEQKBgGHXc3Q7SmCBRbOyQrQQk0m6i+V8328W1S5m2bPg M62aWXMOMn976ZRT1pBDSwz1Y5yJ3NDf7gTZLjEwpgCNrFCJRcc4HLL0NDL8V5js VjvpUU5GyYdsJdb+M4ZUPHi/QEaqzqPQumwJSLlJEdfWirZWVj9dDA8XcpGwQjjy psHRAoGBAJUTgeJYhjK7k5sgfh+PRqiRJP0msIH8FK7SenBGRUkelWrW6td2Riey EcOCMFkRWBeDgnZN5xDyWLBgrzpw9iHQQIUyyBaFknQcRUYKHkCx+k+fr0KHHCUb X2Kvf0rbeMucb4y/h7950HkBBq83AYKMAoI8Ql3cx7pKmyOLXRov -----END RSA PRIVATE KEY-----libmongoc-1.3.1/orchestration_configs/certificates/client.pem000066400000000000000000000055331264720626300245250ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDXTCCAkWgAwIBAgIBAzANBgkqhkiG9w0BAQUFADB0MRcwFQYDVQQDEw5LZXJu ZWwgVGVzdCBDQTEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RCMRYw FAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkGA1UE BhMCVVMwHhcNMTQwNzE3MTYwMDAwWhcNMjAwNzE3MTYwMDAwWjBwMQ8wDQYDVQQD EwZjbGllbnQxEzARBgNVBAsTCktlcm5lbFVzZXIxEDAOBgNVBAoTB01vbmdvREIx FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD VQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJIFboAk9Fdi DY5Xld2iw36vB3IpHEfgWIimd+l1HX4jyp35i6xoqkZZHJUL/NMbUFJ6+44EfFJ5 biB1y1Twr6GqpYp/3R30jKQU4PowO7DSal38MR34yiRFYPG4ZPPXXfwPSuwKrSNo bjqa0/DRJRVQlnGwzJkPsWxIgCjc8KNO/dSHv/CGymc9TjiFAI0VVOhMok1CBNvc ifwWjGBg5V1s3ItMw9x5qk+b9ff5hiOAGxPiCrr8R0C7RoeXg7ZG8K/TqXbsOZEG AOQPRGcrmqG3t4RNBJpZugarPWW6lr11zMpiPLFTrbq3ZNYB9akdsps4R43TKI4J AOtGMJmK430CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAA+nPgVT4addi13yB6mjW +UhdUkFwtb1Wcg0sLtnNucopHZLlCj5FfDdp1RQxe3CyMonxyHTKkrWtQmVtUyvf C/fjpIKt9A9kAmveMHBiu9FTNTc0sbiXcrEBeHF5cD7N+Uwfoc/4rJm0WjEGNkAd pYLCCLVZXPVr3bnc3ZLY1dFZPsJrdH3nJGMjLgUmoNsKnaGozcjiKiXqm6doFzkg 0Le5yD4C/QTaie2ycFa1X5bJfrgoMP7NqKko05h4l0B0+DnjpoTJN+zRreNTMKvE ETGvpUu0IYGxe8ZVAFnlEO/lUeMrPFvH+nDmJYsxO1Sjpds2hi1M1JoeyrTQPwXj 2Q== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAkgVugCT0V2INjleV3aLDfq8HcikcR+BYiKZ36XUdfiPKnfmL rGiqRlkclQv80xtQUnr7jgR8UnluIHXLVPCvoaqlin/dHfSMpBTg+jA7sNJqXfwx HfjKJEVg8bhk89dd/A9K7AqtI2huOprT8NElFVCWcbDMmQ+xbEiAKNzwo0791Ie/ 8IbKZz1OOIUAjRVU6EyiTUIE29yJ/BaMYGDlXWzci0zD3HmqT5v19/mGI4AbE+IK uvxHQLtGh5eDtkbwr9Opduw5kQYA5A9EZyuaobe3hE0Emlm6Bqs9ZbqWvXXMymI8 sVOturdk1gH1qR2ymzhHjdMojgkA60YwmYrjfQIDAQABAoIBAB249VEoNIRE9TVw JpVCuEBlKELYk2UeCWdnWykuKZ6vcmLNlNy3QVGoeeTs172w5ZykY+f4icXP6da5 o3XauCVUMvYKKNwcFzSe+1xxzPSlH/mZh/Xt2left6f8PLBVuk/AXSPG2I9Ihodv VIzERaQdD0J9FmhhhV/hMhUfQ+w5rTCaDpq1KVGU61ks+JAtlQ46g+cvPF9c80cI TEC875n2LqWKmLRN43JUnctV3uGTmolIqCRMHPAs/egl+lG2RXJjqXSQ2uFLOvC/ PXtBb597yadSs2BWPnTu/r7LbLGBAExzlQK1uFsTvuKsBPb3qrvUux0L68qwPuiv W24N8BECgYEAydtAvVB7OymQEX3mck2j7ixDN01wc1ZaCLBDvYPYS/Pvzq4MBiAD lHRtbIa6HPGA5jskbccPqQn8WGnJWCaYvCQryvgaA+BBgo1UTLfQJUo/7N5517vv KvbUa6NF0nj3VwfDV1vvy+amoWi9NOVn6qOh0K84PF4gwagb1EVy9MsCgYEAuTAt KCWdZ/aNcKgJc4NCUqBpLPF7EQypX14teixrbF/IRNS1YC9S20hpkG25HMBXjpBe tVg/MJe8R8CKzYjCt3z5Ff1bUQ2bzivbAtgjcaO0Groo8WWjnamQlrIQcvWM7vBf dnIflQ0slxbHfCi3XEe8tj2T69R7wJZ8L7PxR9cCgYEACgwNtt6Qo6s37obzt3DB 3hL57YC/Ph5oMNKFLKOpWm5z2zeyhYOGahc5cxNppBMpNUxwTb6AuwsyMjxhty+E nqi2PU4IDXVWDWd3cLIdfB2r/OA99Ez4ZI0QmaLw0L8QoJZUVL7QurdqR9JsyHs6 puUqIrb195s/yiPR7sjeJe0CgYEAuJviKEd3JxCN52RcJ58OGrh2oKsJ9/EbV0rX Ixfs7th9GMDDHuOOQbNqKOR4yMSlhCU/hKA4PgTFWPIEbOiM08XtuZIb2i0qyNjH N4qnqr166bny3tJnzOAgl1ljNHa8y+UsBTO3cCr17Jh0vL0KLSAGa9XvBAWKaG6b 1iIXwXkCgYAVz+DA1yy0qfXdS1pgPiCJGlGZXpbBcFnqvbpGSclKWyUG4obYCbrb p5VKVfoK7uU0ly60w9+PNIRsX/VN/6SVcoOzKx40qQBMuYfJ72DQrsPjPYvNg/Nb 4SK94Qhp9TlAyXbqKJ02DjtuDim44sGZ8g7b+k3FfoK4OtzNsqdVdQ== -----END RSA PRIVATE KEY-----libmongoc-1.3.1/orchestration_configs/certificates/crl.pem000066400000000000000000000037661264720626300240350ustar00rootroot00000000000000Certificate Revocation List (CRL): Version 2 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: /CN=Kernel Test CA/OU=Kernel/O=MongoDB/L=New York City/ST=New York/C=US Last Update: Aug 21 13:56:28 2014 GMT Next Update: Aug 18 13:56:28 2024 GMT CRL extensions: X509v3 CRL Number: 4096 No Revoked Certificates. Signature Algorithm: sha256WithRSAEncryption 48:1b:0b:b1:89:f5:6f:af:3c:dd:2a:a0:e5:55:04:80:16:b4: 23:98:39:bb:9f:16:c9:25:73:72:c6:a6:73:21:1d:1a:b6:99: fc:47:5e:bc:af:64:29:02:9c:a5:db:15:8a:65:48:3c:4f:a6: cd:35:47:aa:c6:c0:39:f5:a6:88:8f:1b:6c:26:61:4e:10:d7: e2:b0:20:3a:64:92:c1:d3:2a:11:3e:03:e2:50:fd:4e:3c:de: e2:e5:78:dc:8e:07:a5:69:55:13:2b:8f:ae:21:00:42:85:ff: b6:b1:2b:69:08:40:5a:25:8c:fe:57:7f:b1:06:b0:72:ff:61: de:21:59:05:a8:1b:9e:c7:8a:08:ab:f5:bc:51:b3:36:68:0f: 54:65:3c:8d:b7:80:d0:27:01:3e:43:97:89:19:89:0e:c5:01: 2c:55:9f:b6:e4:c8:0b:35:f8:52:45:d3:b4:09:ce:df:73:98: f5:4c:e4:5a:06:ac:63:4c:f8:4d:9c:af:88:fc:19:f7:77:ea: ee:56:18:49:16:ce:62:66:d1:1b:8d:66:33:b5:dc:b1:25:b3: 6c:81:e9:d0:8a:1d:83:61:49:0e:d9:94:6a:46:80:41:d6:b6: 59:a9:30:55:3d:5b:d3:5b:f1:37:ec:2b:76:d0:3a:ac:b2:c8: 7c:77:04:78 -----BEGIN X509 CRL----- MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADB0MRcwFQYDVQQDEw5LZXJuZWwgVGVz dCBDQTEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RCMRYwFAYDVQQH Ew1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkGA1UEBhMCVVMX DTE0MDgyMTEzNTYyOFoXDTI0MDgxODEzNTYyOFqgDzANMAsGA1UdFAQEAgIQADAN BgkqhkiG9w0BAQsFAAOCAQEASBsLsYn1b6883Sqg5VUEgBa0I5g5u58WySVzcsam cyEdGraZ/EdevK9kKQKcpdsVimVIPE+mzTVHqsbAOfWmiI8bbCZhThDX4rAgOmSS wdMqET4D4lD9Tjze4uV43I4HpWlVEyuPriEAQoX/trEraQhAWiWM/ld/sQawcv9h 3iFZBagbnseKCKv1vFGzNmgPVGU8jbeA0CcBPkOXiRmJDsUBLFWftuTICzX4UkXT tAnO33OY9UzkWgasY0z4TZyviPwZ93fq7lYYSRbOYmbRG41mM7XcsSWzbIHp0Iod g2FJDtmUakaAQda2WakwVT1b01vxN+wrdtA6rLLIfHcEeA== -----END X509 CRL----- libmongoc-1.3.1/orchestration_configs/certificates/password_protected.pem000066400000000000000000000060661264720626300271640ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBCTANBgkqhkiG9w0BAQUFADB4MRswGQYDVQQDExJwYXNz d29yZF9wcm90ZWN0ZWQxDzANBgNVBAsTBktlcm5lbDEQMA4GA1UEChMHTW9uZ29E QjEWMBQGA1UEBxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlvcmsxCzAJ BgNVBAYTAlVTMB4XDTE0MDcxNzE2MDAwMFoXDTIwMDcxNzE2MDAwMFoweDEbMBkG A1UEAxMScGFzc3dvcmRfcHJvdGVjdGVkMQ8wDQYDVQQLEwZLZXJuZWwxEDAOBgNV BAoTB01vbmdvREIxFjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5l dyBZb3JrMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALT4r3Hcou2auIOHeihBSjk4bKQTVqI6r/stnkul359SRfKuzVA9gMQaRRDi MJoxczHJzS2FX+wElzBt2EUhfu3qpUJ4gJw7H4WjLx+mNnj/+6b4HUO4eRzH5hTE A+qgDH40qYjFDEjiARvybWo3IlDLeI/uFwlyUj5PZBUBc1LBBzNtCBfJ2MmHLhIx jzTFhkJZll673LL6BPHtJclXCazqKUZDLqObW4Ei6X4hdBOdC8v8Q6GMgC4BxLe0 wsOpKYYeM3il4BtfiqDQB5ZPG0lgo1Y7OOyFHFXBA7oNkK8lykhdyH4iLt5L9mWo VKyZ79VqSODFuCqWo8n8kUTgA/0CAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkq hkiG9w0BAQUFAAOCAQEAntxk8a0HcuPG8Fdjckp6WL+HKQQnUKdvSk06rPF0SHpN Ma4eZcaumROdtAYnPKvtbpq3DRCQlj59dlWPksEcYiXqf56TgcyAz5K5g5z9RbFi ArvAXJNRcDz1080NWGBUTPYyiKWR3PhtlYhJZ4r7fQIWLv4mifXHViw2roXXhsAY ubk9HOtrqE7x6NJXgR24aybxqI6TfAKfM+LJNtMwMFrPC+GHnhqMOs/jHJS38NIB TrKA63TdpYUroVu23/tGLQaJz352qgF4Di91RkUfnI528goj57pX78H8KRsSNVvs KHVNrxtZIez+pxxjBPnyfCH81swkiAPG9fdX+Hcu5A== -----END CERTIFICATE----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI6y3b7IxcANECAggA MB0GCWCGSAFlAwQBAgQQrTslOKC0GZZwq48v7niXYQSCBNBNKsTN7fyw60/EEDH0 JUgxL83Wfb7pNP97/lV5qiclY1mwcKz44kXQaesFTzhiwzAMOpbI/ijEtsNU25wV wtTgjAC3Em/+5/ygrmAu7hgacIRssspovmsgw029E9iOkyBd1VIrDVMi7HLHf0iU 2Zq18QF20az2pXNMDipmVJkpc9NvjSdqka5+375pJuisspEWCDBd11K10jzCWqB5 q3Rm1IIeq+mql6KT1rJcUoeE0facDc9GDYBiF/MfIKQ3FrZy/psqheCfL1UDUMyc mnm9GJO5+bCuHkg8ni0Zo5XXsf2VEFt0yt6lSucoOP43flucQaHnFKcn+5DHjDXv S6Eb5wEG9qWtzwWy/9DfRbkj6FxUgT3SFgizo/uLmdqFCJCnYkHUD1OuYCDmoIXP VTinwgK4lO/vrGfoPQrgJmdlnwHRWYjlB8edMCbmItaj2Esh3FBS12y976+UT0Sk 8n5HsZAEYScDyNArVhrLUZRgF+r+bgZ28TDFO0MISPCAbZjhvq6lygS3dEmdTUW3 cFDe1deNknWxZcv4UpJW4Nq6ckxwXBfTB1VFzjp7/vXrK/Sd9t8zi6vKTO8OTqc4 KrlLXBgz0ouP/cxhYDykUrKXE2Eb0TjeAN1txZWo3fIFzXUvDZCphQEZNUqsFUxH 86V2lwqVzKrFq6UpTgKrfTw/2ePQn9dQgd7iFWDTWjRkbzA5aAgTSVP8xQRoIOeQ epXtP9202kEz3h28SZYK7QBOTTX9xNmV/dzDTsi9nXZ6KtsP/aGFE5hh95jvESx/ wlOBAPW4HR33rSYalvQPE7RjjLZHOKuYIllUBGlTOfgdA+WUXR3KxiLNPdslPBPV +O6aDyerhWoQwE7TFwhP/FpxL/46hOu4iq4fgqfjddBTq8z5jG3c3zzogDjoDzBF LEQDcbenUCGbEQ7zxXsXtr3QinJ+aAejDO38hp1h9ROb5LF53/9H2j/16nby/jPX 7kp2weRSKGJ0B6AVuS9pTsQz4+E3icsIgBWSU6qtcUz2GO2QxnFuvT9LEVnyMNN2 IKMIEKi2FsUMddHGXLULTANlzUMocdHrd5j81eqcFPhMOFOiHpgwiwxqZyBYOLRl Fe7x5dLVWoLgjJagZj8uYnJbExDsfFLjEx8p4Z+rejJIC5CqZLbz9sDgCtIL+92k +x4mlT1Rfmz9pU+RQqik83nFFRBGWxeW9iWWEgocWtmezvnK6E241v78zkqxNkvF JJo7BsBw7DiEHEfLhBZYuqV2q6+kwqgYrzyGIwAJkBGrkYfalVzgR+3/uN04h005 M3jQRpSkDVGYr3JKEAlh3Sc+JD9VPbu6/RXNwy5mY67UCgWGaFwRqJE3DC9aKfNC OET8m8+8oQgFzhw3pNpENsgwR+Sx3K4q0GI3YwxT02pieBFNQaw53O3B3TtoCjkk UsuyIWqcLonwo4I3z0kjU3gEFN+0m4E4/A1DNt0J3rsKN+toCk1FqbxQg9xTZzXu hYmA3HMMwugzXmCanqBhmMsniPg+dRxCIfiHZhLuEpjKxZWcMWcW4M6l/wbM+LbE oDcTuI9ezfPTZ3xA8hNIHBT3MhuI7EJQnvKKvJDJeyX5sAtmSsSFqhEr8QZD8RgV 5H9eOyUdfcWxLlstcq982V0oGg== -----END ENCRYPTED PRIVATE KEY-----libmongoc-1.3.1/orchestration_configs/certificates/server.pem000066400000000000000000000056071264720626300245570ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDfjCCAmagAwIBAgIBBzANBgkqhkiG9w0BAQUFADB0MRcwFQYDVQQDEw5LZXJu ZWwgVGVzdCBDQTEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RCMRYw FAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkGA1UE BhMCVVMwHhcNMTQwNzE3MTYwMDAwWhcNMjAwNzE3MTYwMDAwWjBsMQ8wDQYDVQQD EwZzZXJ2ZXIxDzANBgNVBAsTBktlcm5lbDEQMA4GA1UEChMHTW9uZ29EQjEWMBQG A1UEBxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlvcmsxCzAJBgNVBAYT AlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp76KJeDczBqjSPJj 5f8DHdtrWpQDK9AWNDlslWpi6+pL8hMqwbX0D7hC2r3kAgccMyFoNIudPqIXfXVd 1LOh6vyY+jveRvqjKW/UZVzZeiL4Gy4bhke6R8JRC3O5aMKIAbaiQUAI1Nd8LxIt LGvH+ia/DFza1whgB8ym/uzVQB6igOifJ1qHWJbTtIhDKaW8gvjOhv5R3jzjfLEb R9r5Q0ZyE0lrO27kTkqgBnHKPmu54GSzU/r0HM3B+Sc/6UN+xNhNbuR+LZ+EvJHm r4de8jhW8wivmjTIvte33jlLibQ5nYIHrlpDLEwlzvDGaIio+OfWcgs2WuPk98MU tht0IQIDAQABoyMwITAfBgNVHREEGDAWgglsb2NhbGhvc3SCCTEyNy4wLjAuMTAN BgkqhkiG9w0BAQUFAAOCAQEANoYxvVFsIol09BQA0fwryAye/Z4dYItvKhmwB9VS t99DsmJcyx0P5meB3Ed8SnwkD0NGCm5TkUY/YLacPP9uJ4SkbPkNZ1fRISyShCCn SGgQUJWHbCbcIEj+vssFb91c5RFJbvnenDkQokRvD2VJWspwioeLzuwtARUoMH3Y qg0k0Mn7Bx1bW1Y6xQJHeVlnZtzxfeueoFO55ZRkZ0ceAD/q7q1ohTXi0vMydYgu 1CB6VkDuibGlv56NdjbttPJm2iQoPaez8tZGpBo76N/Z1ydan0ow2pVjDXVOR84Y 2HSZgbHOGBiycNw2W3vfw7uK0OmiPRTFpJCmewDjYwZ/6w== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAp76KJeDczBqjSPJj5f8DHdtrWpQDK9AWNDlslWpi6+pL8hMq wbX0D7hC2r3kAgccMyFoNIudPqIXfXVd1LOh6vyY+jveRvqjKW/UZVzZeiL4Gy4b hke6R8JRC3O5aMKIAbaiQUAI1Nd8LxItLGvH+ia/DFza1whgB8ym/uzVQB6igOif J1qHWJbTtIhDKaW8gvjOhv5R3jzjfLEbR9r5Q0ZyE0lrO27kTkqgBnHKPmu54GSz U/r0HM3B+Sc/6UN+xNhNbuR+LZ+EvJHmr4de8jhW8wivmjTIvte33jlLibQ5nYIH rlpDLEwlzvDGaIio+OfWcgs2WuPk98MUtht0IQIDAQABAoIBACgi1ilECXCouwMc RDzm7Jb7Rk+Q9MVJ79YlG08Q+oRaNjvAzE03PSN5wj1WjDTUALJXPvi7oy82V4qE R6Q6Kvbv46aUJpYzKFEk2dw7ACpSLa1LNfjGNtMusnecA/QF/8bxLReRu8s5mBQn NDnZvCqllLbfjNlAvsF+/UIn5sqFZpAZPMtPwkTAeh5ge8H9JvrG8y8aXsiFGAhV Z7tMZyn8wPCUrRi14NLvVB4hxM66G/tuTp8r9AmeTU+PV+qbCnKXd+v0IS52hvX9 z75OPfAc66nm4bbPCapb6Yx7WaewPXXU0HDxeaT0BeQ/YfoNa5OT+ZOX1KndSfHa VhtmEsECgYEA3m86yYMsNOo+dkhqctNVRw2N+8gTO28GmWxNV9AC+fy1epW9+FNR yTQXpBkRrR7qrd5mF7WBc7vAIiSfVs021RMofzn5B1x7jzkH34VZtlviNdE3TZhx lPinqo0Yy3UEksgsCBJFIofuCmeTLk4ZtqoiZnXr35RYibaZoQdUT4kCgYEAwQ6Y xsKFYFks1+HYl29kR0qUkXFlVbKOhQIlj/dPm0JjZ0xYkUxmzoXD68HrOWgz7hc2 hZaQTgWf+8cRaZNfh7oL+Iglczc2UXuwuUYguYssD/G6/ZPY15PhItgCghaU5Ewy hMwIJ81NENY2EQTgk/Z1KZitXdVJfHl/IPMQgdkCgYASdqkqkPjaa5dDuj8byO8L NtTSUYlHJbAmjBbfcyTMG230/vkF4+SmDuznci1FcYuJYyyWSzqzoKISM3gGfIJQ rYZvCSDiu4qGGPXOWANaX8YnMXalukGzW/CO96dXPB9lD7iX8uxKMX5Q3sgYz+LS hszUNHWf2XB//ehCtZkKAQKBgQCxL2luepeZHx82H9T+38BkYgHLHw0HQzLkxlyd LjlE4QCEjSB4cmukvkZbuYXfEVEgAvQKVW6p/SWhGkpT4Gt8EXftKV9dyF21GVXQ JZnhUOcm1xBsrWYGLXYi2agrpvgONBTlprERfq5tdnz2z8giZL+RZswu45Nnh8bz AcKzuQKBgQCGOQvKvNL5XKKmws/KRkfJbXgsyRT2ubO6pVL9jGQG5wntkeIRaEpT oxFtWMdPx3b3cxtgSP2ojllEiISk87SFIN1zEhHZy/JpTF0GlU1qg3VIaA78M1p2 ZdpUsuqJzYmc3dDbQMepIaqdW4xMoTtZFyenUJyoezz6eWy/NlZ/XQ== -----END RSA PRIVATE KEY-----libmongoc-1.3.1/orchestration_configs/replica_sets/000077500000000000000000000000001264720626300225465ustar00rootroot00000000000000libmongoc-1.3.1/orchestration_configs/replica_sets/auth.json000066400000000000000000000020201264720626300243740ustar00rootroot00000000000000{ "auth_key": "secret", "id": "repl0", "login": "bob", "members": [ { "procParams": { "ipv6": true, "nohttpinterface": true, "journal": true, "noprealloc": true, "nssize": 1, "port": 27017, "smallfiles": true }, "rsParams": { "tags": { "ordinal": "one", "dc": "ny" } } }, { "procParams": { "ipv6": true, "nohttpinterface": true, "journal": true, "noprealloc": true, "nssize": 1, "port": 27018, "smallfiles": true }, "rsParams": { "tags": { "ordinal": "two", "dc": "pa" } } }, { "procParams": { "ipv6": true, "nohttpinterface": true, "journal": true, "noprealloc": true, "nssize": 1, "port": 27019, "smallfiles": true }, "rsParams": { "arbiterOnly": true } } ], "password": "pwd123" } libmongoc-1.3.1/orchestration_configs/replica_sets/basic.json000066400000000000000000000017161264720626300245270ustar00rootroot00000000000000{ "id": "repl0", "members": [ { "procParams": { "ipv6": true, "nohttpinterface": true, "journal": true, "noprealloc": true, "nssize": 1, "port": 27017, "smallfiles": true }, "rsParams": { "tags": { "ordinal": "one", "dc": "ny" } } }, { "procParams": { "ipv6": true, "nohttpinterface": true, "journal": true, "noprealloc": true, "nssize": 1, "port": 27018, "smallfiles": true }, "rsParams": { "tags": { "ordinal": "two", "dc": "pa" } } }, { "procParams": { "ipv6": true, "nohttpinterface": true, "journal": true, "noprealloc": true, "nssize": 1, "port": 27019, "smallfiles": true }, "rsParams": { "arbiterOnly": true } } ] } libmongoc-1.3.1/orchestration_configs/servers/000077500000000000000000000000001264720626300215625ustar00rootroot00000000000000libmongoc-1.3.1/orchestration_configs/servers/auth.json000066400000000000000000000003261264720626300234170ustar00rootroot00000000000000{ "id": "standalone", "auth_key": "secret", "login": "bob", "name": "mongod", "password": "pwd123", "procParams": { "ipv6": true, "logappend": true, "journal": true, "port": 27017 } } libmongoc-1.3.1/orchestration_configs/servers/basic.json000066400000000000000000000001761264720626300235420ustar00rootroot00000000000000{ "name": "mongod", "procParams": { "ipv6": true, "logappend": true, "journal": true, "port": 27017 } } libmongoc-1.3.1/orchestration_configs/servers/mmapv1.json000066400000000000000000000002671264720626300236630ustar00rootroot00000000000000{ "name": "mongod", "procParams": { "ipv6": true, "logappend": true, "journal": true, "storageEngine": "mmapv1", "port": 27017 } } libmongoc-1.3.1/orchestration_configs/servers/ssl.json000066400000000000000000000007061264720626300232610ustar00rootroot00000000000000{ "id" : "standalone", "name": "mongod", "login": "bob", "password": "pwd123", "procParams": { "ipv6": true, "logappend": true, "journal": true, "port": 27017 }, "sslParams": { "sslCAFile": "/tmp/mongoc-test-certificates/ca.pem", "sslOnNormalPorts": true, "sslPEMKeyFile": "/tmp/mongoc-test-certificates/server.pem", "sslWeakCertificateValidation": true } } libmongoc-1.3.1/orchestration_configs/servers/wiredtiger.json000066400000000000000000000002731264720626300246240ustar00rootroot00000000000000{ "name": "mongod", "procParams": { "ipv6": true, "logappend": true, "journal": true, "storageEngine": "wiredTiger", "port": 27017 } } libmongoc-1.3.1/orchestration_configs/sharded_clusters/000077500000000000000000000000001264720626300234275ustar00rootroot00000000000000libmongoc-1.3.1/orchestration_configs/sharded_clusters/auth.json000066400000000000000000000010641264720626300252640ustar00rootroot00000000000000{ "id": "shard_cluster_1", "login": "bob", "password": "pwd123", "auth_key": "secret", "configsvrs": [ { "port": 27117 }, { "port": 27118 }, { "port": 27119 } ], "shards": [ { "id": "sh01", "shardParams": { "procParams": { "port": 27217 } } }, { "id": "sh02", "shardParams": { "procParams": { "port": 27218 } } } ], "routers": [ { "port": 27017 }, { "port": 27018 } ] } libmongoc-1.3.1/orchestration_configs/sharded_clusters/basic.json000066400000000000000000000007621264720626300254100ustar00rootroot00000000000000{ "id": "shard_cluster_1", "configsvrs": [ { "port": 27117 }, { "port": 27118 }, { "port": 27119 } ], "shards": [ { "id": "sh01", "shardParams": { "procParams": { "port": 27217 } } }, { "id": "sh02", "shardParams": { "procParams": { "port": 27218 } } } ], "routers": [ { "port": 27017 }, { "port": 27018 } ] } libmongoc-1.3.1/src/000077500000000000000000000000001264720626300142645ustar00rootroot00000000000000libmongoc-1.3.1/src/Makefile.am000066400000000000000000000035321264720626300163230ustar00rootroot00000000000000pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = \ $(top_builddir)/src/libmongoc-1.0.pc \ $(top_builddir)/src/libmongoc-priv.pc if ENABLE_SSL pkgconfig_DATA += $(top_builddir)/src/libmongoc-ssl-1.0.pc endif lib_LTLIBRARIES += libmongoc-priv.la lib_LTLIBRARIES += libmongoc-1.0.la MONGOC_CPPFLAGS_SHARED = \ -DMONGOC_COMPILATION \ $(LIBC_FEATURES) \ $(OPTIMIZE_CFLAGS) \ $(COVERAGE_CFLAGS) \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/mongoc \ -I$(top_builddir)/src/mongoc \ $(BSON_CFLAGS) \ $(PTHREAD_CFLAGS) \ $(SSL_CFLAGS) \ $(SASL_CFLAGS) if OS_SOLARIS MONGOC_CPPFLAGS_SHARED += -D_REENTRANT endif if !ENABLE_DEBUG MONGOC_CPPFLAGS_SHARED += \ -DBSON_DISABLE_ASSERT \ -DBSON_DISABLE_CHECKS endif libmongoc_priv_la_CPPFLAGS = $(MONGOC_CPPFLAGS_SHARED) libmongoc_1_0_la_CPPFLAGS = $(MONGOC_CPPFLAGS_SHARED) MONGOC_LDFLAGS_SHARED = $(OPTIMIZE_LDFLAGS) $(COVERAGE_LDFLAGS) libmongoc_priv_la_LDFLAGS = \ $(MONGOC_LDFLAGS_SHARED) \ -no-undefined libmongoc_1_0_la_LDFLAGS = \ $(MONGOC_LDFLAGS_SHARED) \ -no-undefined \ -rpath $(libdir) if HAVE_LD_VERSION_SCRIPT libmongoc_1_0_la_LDFLAGS += -Wl,--version-script=$(srcdir)/build/autotools/versions.ldscript else libmongoc_1_0_la_LDFLAGS += -export-symbols-regex "^mongoc_" endif MONGOC_LIBADD_SHARED = \ $(BSON_LIBS) \ $(PTHREAD_LIBS) \ $(SHM_LIB) \ $(SSL_LIBS) \ $(SASL_LIBS) if OS_WIN32 MONGOC_LIBADD_SHARED += -lws2_32 endif libmongoc_priv_la_LIBADD = $(MONGOC_LIBADD_SHARED) libmongoc_1_0_la_LIBADD = $(MONGOC_LIBADD_SHARED) # Sources defined in src/mongoc/Makefile.am MONGOC_SOURCES_SHARED = libmongoc_1_0_la_SOURCES = $(MONGOC_SOURCES_SHARED) libmongoc_priv_la_SOURCES = $(MONGOC_SOURCES_SHARED) include src/mongoc/Makefile.am include src/tools/Makefile.am EXTRA_DIST += \ src/libmongoc.symbols \ build/autotools/versions.ldscript \ src/libmongoc-1.0.pc.in \ src/libmongoc-ssl-1.0.pc.in libmongoc-1.3.1/src/libbson/000077500000000000000000000000001264720626300157145ustar00rootroot00000000000000libmongoc-1.3.1/src/libmongoc-1.0.pc.in000066400000000000000000000004741264720626300174670ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=${exec_prefix}/include Name: libmongoc Description: The libmongoc MongoDB client library. Version: @VERSION@ Requires: libbson-1.0 Libs: @SASL_LIBS@ @SSL_LIBS@ @SHM_LIB@ -L${libdir} -lmongoc-1.0 Cflags: -I${includedir}/libmongoc-@MONGOC_API_VERSION@ libmongoc-1.3.1/src/libmongoc-priv.pc.in000066400000000000000000000005741264720626300201520ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=${exec_prefix}/include Name: libmongoc-priv Description: The libmongoc MongoDB client library, with access to private structures. Version: @VERSION@ Requires: libbson-1.0 Libs: @SASL_LIBS@ @SSL_LIBS@ @SHM_LIB@ -L${libdir} -lmongoc-priv Cflags: -DMONGOC_I_AM_A_DRIVER -I${includedir}/libmongoc-@MONGOC_API_VERSION@ libmongoc-1.3.1/src/libmongoc-ssl-1.0.pc.in000066400000000000000000000004001264720626300202530ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=${exec_prefix}/include Name: libmongoc-@MONGOC_API_VERSION@ Description: SSL support for the libmongoc-@MONGOC_API_VERSION@ library. Version: @VERSION@ Requires: libmongoc-1.0 Libs: Cflags: libmongoc-1.3.1/src/libmongoc.symbols000066400000000000000000000167551264720626300176650ustar00rootroot00000000000000LIBMONGOC_1.0 LIBMONGOC_1.1 LIBMONGOC_1.2 LIBMONGOC_1.3 mongoc_bulk_operation_delete mongoc_bulk_operation_delete_one mongoc_bulk_operation_destroy mongoc_bulk_operation_execute mongoc_bulk_operation_get_write_concern mongoc_bulk_operation_insert mongoc_bulk_operation_new mongoc_bulk_operation_remove mongoc_bulk_operation_remove_one mongoc_bulk_operation_replace_one mongoc_bulk_operation_set_bypass_document_validation mongoc_bulk_operation_set_client mongoc_bulk_operation_set_collection mongoc_bulk_operation_set_database mongoc_bulk_operation_set_hint mongoc_bulk_operation_set_write_concern mongoc_bulk_operation_update mongoc_bulk_operation_update_one mongoc_check_version mongoc_cleanup mongoc_client_command mongoc_client_command_simple mongoc_client_destroy mongoc_client_find_databases mongoc_client_get_collection mongoc_client_get_database mongoc_client_get_database_names mongoc_client_get_default_database mongoc_client_get_gridfs mongoc_client_get_max_bson_size mongoc_client_get_max_message_size mongoc_client_get_read_concern mongoc_client_get_read_prefs mongoc_client_get_server_status mongoc_client_get_uri mongoc_client_get_write_concern mongoc_client_kill_cursor mongoc_client_new mongoc_client_new_from_uri mongoc_client_pool_destroy mongoc_client_pool_max_size mongoc_client_pool_min_size mongoc_client_pool_new mongoc_client_pool_pop mongoc_client_pool_push mongoc_client_pool_set_ssl_opts mongoc_client_pool_try_pop mongoc_client_set_read_concern mongoc_client_set_read_prefs mongoc_client_set_ssl_opts mongoc_client_set_stream_initiator mongoc_client_set_write_concern mongoc_collection_aggregate mongoc_collection_command mongoc_collection_command_simple mongoc_collection_copy mongoc_collection_count mongoc_collection_count_with_opts mongoc_collection_create_bulk_operation mongoc_collection_create_index mongoc_collection_delete mongoc_collection_destroy mongoc_collection_drop mongoc_collection_drop_index mongoc_collection_ensure_index mongoc_collection_find mongoc_collection_find_and_modify mongoc_collection_find_and_modify_with_opts mongoc_collection_find_indexes mongoc_collection_get_last_error mongoc_collection_get_name mongoc_collection_get_read_concern mongoc_collection_get_read_prefs mongoc_collection_get_write_concern mongoc_collection_insert mongoc_collection_insert_bulk mongoc_collection_keys_to_index_string mongoc_collection_remove mongoc_collection_rename mongoc_collection_save mongoc_collection_set_read_concern mongoc_collection_set_read_prefs mongoc_collection_set_write_concern mongoc_collection_stats mongoc_collection_update mongoc_collection_validate mongoc_cursor_clone mongoc_cursor_current mongoc_cursor_destroy mongoc_cursor_error mongoc_cursor_get_batch_size mongoc_cursor_get_hint mongoc_cursor_get_host mongoc_cursor_get_id mongoc_cursor_get_max_await_time_ms mongoc_cursor_is_alive mongoc_cursor_more mongoc_cursor_next mongoc_cursor_set_batch_size mongoc_cursor_set_max_await_time_ms mongoc_database_add_user mongoc_database_command mongoc_database_command_simple mongoc_database_copy mongoc_database_create_collection mongoc_database_destroy mongoc_database_drop mongoc_database_find_collections mongoc_database_get_collection mongoc_database_get_collection_names mongoc_database_get_name mongoc_database_get_read_concern mongoc_database_get_read_prefs mongoc_database_get_write_concern mongoc_database_has_collection mongoc_database_remove_all_users mongoc_database_remove_user mongoc_database_set_read_concern mongoc_database_set_read_prefs mongoc_database_set_write_concern mongoc_find_and_modify_opts_destroy mongoc_find_and_modify_opts_new mongoc_find_and_modify_opts_set_bypass_document_validation mongoc_find_and_modify_opts_set_fields mongoc_find_and_modify_opts_set_flags mongoc_find_and_modify_opts_set_sort mongoc_find_and_modify_opts_set_update mongoc_get_major_version mongoc_get_micro_version mongoc_get_minor_version mongoc_get_version mongoc_gridfs_create_file mongoc_gridfs_create_file_from_stream mongoc_gridfs_destroy mongoc_gridfs_drop mongoc_gridfs_file_destroy mongoc_gridfs_file_error mongoc_gridfs_file_get_aliases mongoc_gridfs_file_get_chunk_size mongoc_gridfs_file_get_content_type mongoc_gridfs_file_get_filename mongoc_gridfs_file_get_id mongoc_gridfs_file_get_length mongoc_gridfs_file_get_md5 mongoc_gridfs_file_get_metadata mongoc_gridfs_file_get_upload_date mongoc_gridfs_file_list_destroy mongoc_gridfs_file_list_error mongoc_gridfs_file_list_next mongoc_gridfs_file_readv mongoc_gridfs_file_remove mongoc_gridfs_file_save mongoc_gridfs_file_seek mongoc_gridfs_file_set_aliases mongoc_gridfs_file_set_content_type mongoc_gridfs_file_set_filename mongoc_gridfs_file_set_md5 mongoc_gridfs_file_set_metadata mongoc_gridfs_file_tell mongoc_gridfs_file_writev mongoc_gridfs_find mongoc_gridfs_find_one mongoc_gridfs_find_one_by_filename mongoc_gridfs_get_chunks mongoc_gridfs_get_files mongoc_gridfs_remove_by_filename mongoc_index_opt_geo_get_default mongoc_index_opt_geo_init mongoc_index_opt_get_default mongoc_index_opt_init mongoc_index_opt_wt_get_default mongoc_index_opt_wt_init mongoc_init mongoc_log mongoc_log_default_handler mongoc_log_level_str mongoc_log_set_handler mongoc_matcher_destroy mongoc_matcher_match mongoc_matcher_new mongoc_rand_add mongoc_rand_seed mongoc_rand_status mongoc_read_concern_copy mongoc_read_concern_destroy mongoc_read_concern_get_level mongoc_read_concern_new mongoc_read_concern_set_level mongoc_read_prefs_add_tag mongoc_read_prefs_copy mongoc_read_prefs_destroy mongoc_read_prefs_get_mode mongoc_read_prefs_get_tags mongoc_read_prefs_is_valid mongoc_read_prefs_new mongoc_read_prefs_set_mode mongoc_read_prefs_set_tags mongoc_server_description_destroy mongoc_server_description_host mongoc_server_description_id mongoc_server_description_new_copy mongoc_socket_accept mongoc_socket_bind mongoc_socket_check_closed mongoc_socket_close mongoc_socket_connect mongoc_socket_destroy mongoc_socket_errno mongoc_socket_getnameinfo mongoc_socket_getsockname mongoc_socket_inet_ntop mongoc_socket_listen mongoc_socket_new mongoc_socket_recv mongoc_socket_send mongoc_socket_sendv mongoc_socket_setsockopt mongoc_ssl_opt_get_default mongoc_stream_buffered_new mongoc_stream_check_closed mongoc_stream_close mongoc_stream_destroy mongoc_stream_failed mongoc_stream_file_get_fd mongoc_stream_file_new mongoc_stream_file_new_for_path mongoc_stream_flush mongoc_stream_get_base_stream mongoc_stream_gridfs_new mongoc_stream_read mongoc_stream_readv mongoc_stream_setsockopt mongoc_stream_socket_get_socket mongoc_stream_socket_new mongoc_stream_tls_check_cert mongoc_stream_tls_do_handshake mongoc_stream_tls_new mongoc_stream_write mongoc_stream_writev mongoc_uri_copy mongoc_uri_destroy mongoc_uri_get_auth_mechanism mongoc_uri_get_auth_source mongoc_uri_get_credentials mongoc_uri_get_database mongoc_uri_get_hosts mongoc_uri_get_mechanism_properties mongoc_uri_get_options mongoc_uri_get_password mongoc_uri_get_read_concern mongoc_uri_get_read_prefs mongoc_uri_get_read_prefs_t mongoc_uri_get_replica_set mongoc_uri_get_ssl mongoc_uri_get_string mongoc_uri_get_username mongoc_uri_get_write_concern mongoc_uri_new mongoc_uri_new_for_host_port mongoc_uri_unescape mongoc_write_concern_copy mongoc_write_concern_destroy mongoc_write_concern_get_fsync mongoc_write_concern_get_journal mongoc_write_concern_get_w mongoc_write_concern_get_wmajority mongoc_write_concern_get_wtag mongoc_write_concern_get_wtimeout mongoc_write_concern_new mongoc_write_concern_set_fsync mongoc_write_concern_set_journal mongoc_write_concern_set_w mongoc_write_concern_set_wmajority mongoc_write_concern_set_wtag mongoc_write_concern_set_wtimeout libmongoc-1.3.1/src/mongoc/000077500000000000000000000000001264720626300155465ustar00rootroot00000000000000libmongoc-1.3.1/src/mongoc/.gitignore000066400000000000000000000000411264720626300175310ustar00rootroot00000000000000mongoc-config.h mongoc-version.h libmongoc-1.3.1/src/mongoc/Makefile.am000066400000000000000000000133061264720626300176050ustar00rootroot00000000000000headerdir = $(prefix)/include/libmongoc-@MONGOC_API_VERSION@ header_DATA = \ $(INST_H_FILES) \ $(MONGOC_DEF_FILES) \ src/mongoc/mongoc-config.h MONGOC_DEF_FILES = \ src/mongoc/op-delete.def \ src/mongoc/op-get-more.def \ src/mongoc/op-header.def \ src/mongoc/op-insert.def \ src/mongoc/op-kill-cursors.def \ src/mongoc/op-msg.def \ src/mongoc/op-query.def \ src/mongoc/op-reply.def \ src/mongoc/op-update.def \ src/mongoc/mongoc-counters.defs INST_H_FILES = \ src/mongoc/mongoc.h \ src/mongoc/mongoc-array-private.h \ src/mongoc/mongoc-async-private.h \ src/mongoc/mongoc-async-cmd-private.h \ src/mongoc/mongoc-b64-private.h \ src/mongoc/mongoc-buffer-private.h \ src/mongoc/mongoc-bulk-operation-private.h \ src/mongoc/mongoc-bulk-operation.h \ src/mongoc/mongoc-client-pool.h \ src/mongoc/mongoc-client-pool-private.h \ src/mongoc/mongoc-client-private.h \ src/mongoc/mongoc-client.h \ src/mongoc/mongoc-cluster-private.h \ src/mongoc/mongoc-collection-private.h \ src/mongoc/mongoc-collection.h \ src/mongoc/mongoc-counters-private.h \ src/mongoc/mongoc-cursor-array-private.h \ src/mongoc/mongoc-cursor-cursorid-private.h \ src/mongoc/mongoc-cursor-transform-private.h \ src/mongoc/mongoc-cursor-private.h \ src/mongoc/mongoc-cursor.h \ src/mongoc/mongoc-database-private.h \ src/mongoc/mongoc-database.h \ src/mongoc/mongoc-errno-private.h \ src/mongoc/mongoc-error.h \ src/mongoc/mongoc-find-and-modify-private.h \ src/mongoc/mongoc-find-and-modify.h \ src/mongoc/mongoc-flags.h \ src/mongoc/mongoc-gridfs-file-list-private.h \ src/mongoc/mongoc-gridfs-file-list.h \ src/mongoc/mongoc-gridfs-file-page-private.h \ src/mongoc/mongoc-gridfs-file-page.h \ src/mongoc/mongoc-gridfs-file-private.h \ src/mongoc/mongoc-gridfs-file.h \ src/mongoc/mongoc-gridfs-private.h \ src/mongoc/mongoc-gridfs.h \ src/mongoc/mongoc-host-list-private.h \ src/mongoc/mongoc-host-list.h \ src/mongoc/mongoc-index.h \ src/mongoc/mongoc-init.h \ src/mongoc/mongoc-iovec.h \ src/mongoc/mongoc-list-private.h \ src/mongoc/mongoc-log.h \ src/mongoc/mongoc-log-private.h \ src/mongoc/mongoc-matcher-op-private.h \ src/mongoc/mongoc-matcher-private.h \ src/mongoc/mongoc-matcher.h \ src/mongoc/mongoc-memcmp-private.h \ src/mongoc/mongoc-opcode.h \ src/mongoc/mongoc-opcode-private.h \ src/mongoc/mongoc-queue-private.h \ src/mongoc/mongoc-read-concern-private.h \ src/mongoc/mongoc-read-concern.h \ src/mongoc/mongoc-read-prefs-private.h \ src/mongoc/mongoc-read-prefs.h \ src/mongoc/mongoc-rpc-private.h \ src/mongoc/mongoc-sasl-private.h \ src/mongoc/mongoc-scram-private.h \ src/mongoc/mongoc-server-description.h \ src/mongoc/mongoc-server-description-private.h \ src/mongoc/mongoc-server-stream-private.h \ src/mongoc/mongoc-set-private.h \ src/mongoc/mongoc-socket.h \ src/mongoc/mongoc-socket-private.h \ src/mongoc/mongoc-ssl-private.h \ src/mongoc/mongoc-stream-buffered.h \ src/mongoc/mongoc-stream-file.h \ src/mongoc/mongoc-stream-gridfs.h \ src/mongoc/mongoc-stream-private.h \ src/mongoc/mongoc-stream-socket.h \ src/mongoc/mongoc-stream.h \ src/mongoc/mongoc-thread-private.h \ src/mongoc/mongoc-topology-description-private.h \ src/mongoc/mongoc-topology-private.h \ src/mongoc/mongoc-topology-scanner-private.h \ src/mongoc/mongoc-trace.h \ src/mongoc/mongoc-uri.h \ src/mongoc/mongoc-uri-private.h \ src/mongoc/mongoc-util-private.h \ src/mongoc/mongoc-version.h \ src/mongoc/mongoc-version-functions.h \ src/mongoc/mongoc-write-command-private.h \ src/mongoc/mongoc-write-concern-private.h \ src/mongoc/mongoc-write-concern.h \ src/mongoc/utlist.h if ENABLE_SSL INST_H_FILES += \ src/mongoc/mongoc-rand.h \ src/mongoc/mongoc-rand-private.h \ src/mongoc/mongoc-stream-tls.h \ src/mongoc/mongoc-ssl.h endif MONGOC_SOURCES_SHARED += \ $(INST_H_FILES) \ src/mongoc/mongoc-array.c \ src/mongoc/mongoc-async.c \ src/mongoc/mongoc-async-cmd.c \ src/mongoc/mongoc-buffer.c \ src/mongoc/mongoc-bulk-operation.c \ src/mongoc/mongoc-b64.c \ src/mongoc/mongoc-client.c \ src/mongoc/mongoc-client-pool.c \ src/mongoc/mongoc-cluster.c \ src/mongoc/mongoc-collection.c \ src/mongoc/mongoc-counters.c \ src/mongoc/mongoc-cursor.c \ src/mongoc/mongoc-cursor-array.c \ src/mongoc/mongoc-cursor-cursorid.c \ src/mongoc/mongoc-cursor-transform.c \ src/mongoc/mongoc-database.c \ src/mongoc/mongoc-find-and-modify.c \ src/mongoc/mongoc-host-list.c \ src/mongoc/mongoc-init.c \ src/mongoc/mongoc-gridfs.c \ src/mongoc/mongoc-gridfs-file.c \ src/mongoc/mongoc-gridfs-file-page.c \ src/mongoc/mongoc-gridfs-file-list.c \ src/mongoc/mongoc-index.c \ src/mongoc/mongoc-list.c \ src/mongoc/mongoc-log.c \ src/mongoc/mongoc-matcher-op.c \ src/mongoc/mongoc-matcher.c \ src/mongoc/mongoc-memcmp.c \ src/mongoc/mongoc-opcode.c \ src/mongoc/mongoc-queue.c \ src/mongoc/mongoc-read-concern.c \ src/mongoc/mongoc-read-prefs.c \ src/mongoc/mongoc-rpc.c \ src/mongoc/mongoc-server-description.c \ src/mongoc/mongoc-server-stream.c \ src/mongoc/mongoc-set.c \ src/mongoc/mongoc-socket.c \ src/mongoc/mongoc-stream.c \ src/mongoc/mongoc-stream-buffered.c \ src/mongoc/mongoc-stream-file.c \ src/mongoc/mongoc-stream-gridfs.c \ src/mongoc/mongoc-stream-socket.c \ src/mongoc/mongoc-topology.c \ src/mongoc/mongoc-topology-description.c \ src/mongoc/mongoc-topology-scanner.c \ src/mongoc/mongoc-uri.c \ src/mongoc/mongoc-util.c \ src/mongoc/mongoc-version-functions.c \ src/mongoc/mongoc-write-command.c \ src/mongoc/mongoc-write-concern.c if ENABLE_SSL MONGOC_SOURCES_SHARED += \ src/mongoc/mongoc-rand.c \ src/mongoc/mongoc-scram.c \ src/mongoc/mongoc-stream-tls.c \ src/mongoc/mongoc-ssl.c endif if ENABLE_SASL MONGOC_SOURCES_SHARED += src/mongoc/mongoc-sasl.c endif EXTRA_DIST += $(MONGOC_DEF_FILES) libmongoc-1.3.1/src/mongoc/indent000077500000000000000000000001101264720626300167450ustar00rootroot00000000000000#!/bin/sh uncrustify --replace -l C -c uncrustify.cfg --no-backup "$@" libmongoc-1.3.1/src/mongoc/mongoc-array-private.h000066400000000000000000000032261264720626300217700ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_ARRAY_PRIVATE_H #define MONGOC_ARRAY_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef struct _mongoc_array_t mongoc_array_t; struct _mongoc_array_t { size_t len; size_t element_size; size_t allocated; void *data; }; #define _mongoc_array_append_val(a, v) _mongoc_array_append_vals(a, &v, 1) #define _mongoc_array_index(a, t, i) (((t*)(a)->data)[i]) #define _mongoc_array_clear(a) (a)->len = 0 void _mongoc_array_init (mongoc_array_t *array, size_t element_size); void _mongoc_array_copy (mongoc_array_t *dst, const mongoc_array_t *src); void _mongoc_array_append_vals (mongoc_array_t *array, const void *data, uint32_t n_elements); void _mongoc_array_destroy (mongoc_array_t *array); BSON_END_DECLS #endif /* MONGOC_ARRAY_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-array.c000066400000000000000000000045061264720626300203150ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-array-private.h" void _mongoc_array_init (mongoc_array_t *array, size_t element_size) { BSON_ASSERT (array); BSON_ASSERT (element_size); array->len = 0; array->element_size = element_size; array->allocated = 128; array->data = (void *)bson_malloc0(array->allocated); } /* *-------------------------------------------------------------------------- * * _mongoc_array_copy -- * * Destroy dst and copy src into it. Both arrays must be initialized. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void _mongoc_array_copy (mongoc_array_t *dst, const mongoc_array_t *src) { _mongoc_array_destroy (dst); dst->len = src->len; dst->element_size = src->element_size; dst->allocated = src->allocated; dst->data = (void *)bson_malloc (dst->allocated); memcpy (dst->data, src->data, dst->allocated); } void _mongoc_array_destroy (mongoc_array_t *array) { if (array && array->data) { bson_free(array->data); } } void _mongoc_array_append_vals (mongoc_array_t *array, const void *data, uint32_t n_elements) { size_t len; size_t off; size_t next_size; BSON_ASSERT (array); BSON_ASSERT (data); off = array->element_size * array->len; len = (size_t)n_elements * array->element_size; if ((off + len) > array->allocated) { next_size = bson_next_power_of_two(off + len); array->data = (void *)bson_realloc(array->data, next_size); array->allocated = next_size; } memcpy((uint8_t *)array->data + off, data, len); array->len += n_elements; } libmongoc-1.3.1/src/mongoc/mongoc-async-cmd-private.h000066400000000000000000000061261264720626300225320ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_ASYNC_CMD_PRIVATE_H #define MONGOC_ASYNC_CMD_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-client.h" #include "mongoc-async-private.h" #include "mongoc-array-private.h" #include "mongoc-buffer-private.h" #include "mongoc-rpc-private.h" #include "mongoc-stream.h" BSON_BEGIN_DECLS typedef enum { MONGOC_ASYNC_CMD_SETUP, MONGOC_ASYNC_CMD_SEND, MONGOC_ASYNC_CMD_RECV_LEN, MONGOC_ASYNC_CMD_RECV_RPC, MONGOC_ASYNC_CMD_ERROR_STATE, MONGOC_ASYNC_CMD_CANCELED_STATE, } mongoc_async_cmd_state_t; typedef struct _mongoc_async_cmd { mongoc_stream_t *stream; mongoc_async_t *async; mongoc_async_cmd_state_t state; int events; mongoc_async_cmd_setup_t setup; void *setup_ctx; mongoc_async_cmd_cb_t cb; void *data; bson_error_t error; int64_t start_time; int64_t expire_at; bson_t cmd; mongoc_buffer_t buffer; mongoc_array_t array; mongoc_iovec_t *iovec; size_t niovec; size_t bytes_to_read; mongoc_rpc_t rpc; bson_t reply; bool reply_needs_cleanup; char ns[MONGOC_NAMESPACE_MAX]; struct _mongoc_async_cmd *next; struct _mongoc_async_cmd *prev; } mongoc_async_cmd_t; mongoc_async_cmd_t * mongoc_async_cmd_new (mongoc_async_t *async, mongoc_stream_t *stream, mongoc_async_cmd_setup_t setup, void *setup_ctx, const char *dbname, const bson_t *cmd, mongoc_async_cmd_cb_t cb, void *cb_data, int32_t timeout_msec); void mongoc_async_cmd_destroy (mongoc_async_cmd_t *acmd); bool mongoc_async_cmd_run (mongoc_async_cmd_t *acmd); #ifdef MONGOC_ENABLE_SSL int mongoc_async_cmd_tls_setup (mongoc_stream_t *stream, int *events, void *ctx, int32_t timeout_msec, bson_error_t *error); #endif BSON_END_DECLS #endif /* MONGOC_ASYNC_CMD_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-async-cmd.c000066400000000000000000000273411264720626300210570ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-client.h" #include "mongoc-async-cmd-private.h" #include "mongoc-async-private.h" #include "mongoc-error.h" #include "mongoc-opcode.h" #include "mongoc-rpc-private.h" #include "mongoc-stream-private.h" #include "mongoc-server-description-private.h" #include "utlist.h" #ifdef MONGOC_ENABLE_SSL #include "mongoc-stream-tls.h" #endif #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "async" typedef mongoc_async_cmd_result_t (*_mongoc_async_cmd_phase_t)( mongoc_async_cmd_t *cmd); mongoc_async_cmd_result_t _mongoc_async_cmd_phase_setup (mongoc_async_cmd_t *cmd); mongoc_async_cmd_result_t _mongoc_async_cmd_phase_send (mongoc_async_cmd_t *cmd); mongoc_async_cmd_result_t _mongoc_async_cmd_phase_recv_len (mongoc_async_cmd_t *cmd); mongoc_async_cmd_result_t _mongoc_async_cmd_phase_recv_rpc (mongoc_async_cmd_t *cmd); static const _mongoc_async_cmd_phase_t gMongocCMDPhases[] = { _mongoc_async_cmd_phase_setup, _mongoc_async_cmd_phase_send, _mongoc_async_cmd_phase_recv_len, _mongoc_async_cmd_phase_recv_rpc, NULL, /* no callback for MONGOC_ASYNC_CMD_ERROR_STATE */ NULL, /* no callback for MONGOC_ASYNC_CMD_CANCELED_STATE */ }; #ifdef MONGOC_ENABLE_SSL int mongoc_async_cmd_tls_setup (mongoc_stream_t *stream, int *events, void *ctx, int32_t timeout_msec, bson_error_t *error) { mongoc_stream_t *tls_stream; const char *host = (const char *)ctx; for (tls_stream = stream; tls_stream->type != MONGOC_STREAM_TLS; tls_stream = mongoc_stream_get_base_stream (tls_stream)) { } if (mongoc_stream_tls_do_handshake (tls_stream, timeout_msec)) { if (mongoc_stream_tls_check_cert (tls_stream, host)) { return 1; } else { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to verify TLS cert."); return -1; } } else if (mongoc_stream_tls_should_retry (tls_stream)) { *events = mongoc_stream_tls_should_read (tls_stream) ? POLLIN : POLLOUT; } else { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to initialize TLS state."); return -1; } return 0; } #endif bool mongoc_async_cmd_run (mongoc_async_cmd_t *acmd) { mongoc_async_cmd_result_t result; int64_t rtt; _mongoc_async_cmd_phase_t phase_callback; phase_callback = gMongocCMDPhases[acmd->state]; if (phase_callback) { result = phase_callback (acmd); } else { result = MONGOC_ASYNC_CMD_ERROR; } if (result == MONGOC_ASYNC_CMD_IN_PROGRESS) { return true; } rtt = bson_get_monotonic_time () - acmd->start_time; if (result == MONGOC_ASYNC_CMD_SUCCESS) { acmd->cb (result, &acmd->reply, rtt, acmd->data, &acmd->error); } else { /* we're in ERROR, TIMEOUT, or CANCELED */ acmd->cb (result, NULL, rtt, acmd->data, &acmd->error); } mongoc_async_cmd_destroy (acmd); return false; } void _mongoc_async_cmd_init_send (mongoc_async_cmd_t *acmd, const char *dbname) { bson_snprintf (acmd->ns, sizeof acmd->ns, "%s.$cmd", dbname); acmd->rpc.query.msg_len = 0; acmd->rpc.query.request_id = ++acmd->async->request_id; acmd->rpc.query.response_to = 0; acmd->rpc.query.opcode = MONGOC_OPCODE_QUERY; acmd->rpc.query.flags = MONGOC_QUERY_SLAVE_OK; acmd->rpc.query.collection = acmd->ns; acmd->rpc.query.skip = 0; acmd->rpc.query.n_return = -1; acmd->rpc.query.query = bson_get_data (&acmd->cmd); acmd->rpc.query.fields = NULL; _mongoc_rpc_gather (&acmd->rpc, &acmd->array); acmd->iovec = (mongoc_iovec_t *)acmd->array.data; acmd->niovec = acmd->array.len; _mongoc_rpc_swab_to_le (&acmd->rpc); } void _mongoc_async_cmd_state_start (mongoc_async_cmd_t *acmd) { if (acmd->setup) { acmd->state = MONGOC_ASYNC_CMD_SETUP; } else { acmd->state = MONGOC_ASYNC_CMD_SEND; } acmd->events = POLLOUT; } mongoc_async_cmd_t * mongoc_async_cmd_new (mongoc_async_t *async, mongoc_stream_t *stream, mongoc_async_cmd_setup_t setup, void *setup_ctx, const char *dbname, const bson_t *cmd, mongoc_async_cmd_cb_t cb, void *cb_data, int32_t timeout_msec) { mongoc_async_cmd_t *acmd; mongoc_async_cmd_t *tmp; bool found = false; BSON_ASSERT (cmd); BSON_ASSERT (dbname); BSON_ASSERT (stream); acmd = (mongoc_async_cmd_t *)bson_malloc0 (sizeof (*acmd)); acmd->async = async; acmd->expire_at = bson_get_monotonic_time () + (int64_t) timeout_msec * 1000; acmd->stream = stream; acmd->setup = setup; acmd->setup_ctx = setup_ctx; acmd->cb = cb; acmd->data = cb_data; bson_copy_to (cmd, &acmd->cmd); _mongoc_array_init (&acmd->array, sizeof (mongoc_iovec_t)); _mongoc_buffer_init (&acmd->buffer, NULL, 0, NULL, NULL); _mongoc_async_cmd_init_send (acmd, dbname); _mongoc_async_cmd_state_start (acmd); /* slot the cmd into the right place in the expiration list */ { async->ncmds++; DL_FOREACH (async->cmds, tmp) { if (tmp->expire_at >= acmd->expire_at) { DL_PREPEND_ELEM (async->cmds, tmp, acmd); found = true; break; } } if (! found) { DL_APPEND (async->cmds, acmd); } } return acmd; } void mongoc_async_cmd_destroy (mongoc_async_cmd_t *acmd) { BSON_ASSERT (acmd); DL_DELETE (acmd->async->cmds, acmd); acmd->async->ncmds--; bson_destroy (&acmd->cmd); if (acmd->reply_needs_cleanup) { bson_destroy (&acmd->reply); } _mongoc_array_destroy (&acmd->array); _mongoc_buffer_destroy (&acmd->buffer); bson_free (acmd); } mongoc_async_cmd_result_t _mongoc_async_cmd_phase_setup (mongoc_async_cmd_t *acmd) { int64_t now; int64_t timeout_msec; now = bson_get_monotonic_time (); timeout_msec = (acmd->expire_at - now) / 1000; BSON_ASSERT (timeout_msec < INT32_MAX); switch (acmd->setup (acmd->stream, &acmd->events, acmd->setup_ctx, (int32_t) timeout_msec, &acmd->error)) { case -1: return MONGOC_ASYNC_CMD_ERROR; break; case 0: break; case 1: acmd->state = MONGOC_ASYNC_CMD_SEND; acmd->events = POLLOUT; break; default: abort(); } return MONGOC_ASYNC_CMD_IN_PROGRESS; } mongoc_async_cmd_result_t _mongoc_async_cmd_phase_send (mongoc_async_cmd_t *acmd) { ssize_t bytes; bytes = mongoc_stream_writev (acmd->stream, acmd->iovec, acmd->niovec, 0); if (bytes < 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to write rpc bytes."); return MONGOC_ASYNC_CMD_ERROR; } while (bytes) { if (acmd->iovec->iov_len < (size_t)bytes) { bytes -= acmd->iovec->iov_len; acmd->iovec++; acmd->niovec--; } else { acmd->iovec->iov_base = ((char *)acmd->iovec->iov_base) + bytes; acmd->iovec->iov_len -= bytes; bytes = 0; } } acmd->state = MONGOC_ASYNC_CMD_RECV_LEN; acmd->bytes_to_read = 4; acmd->events = POLLIN; acmd->start_time = bson_get_monotonic_time (); return MONGOC_ASYNC_CMD_IN_PROGRESS; } mongoc_async_cmd_result_t _mongoc_async_cmd_phase_recv_len (mongoc_async_cmd_t *acmd) { ssize_t bytes = _mongoc_buffer_try_append_from_stream (&acmd->buffer, acmd->stream, acmd->bytes_to_read, 0, &acmd->error); uint32_t msg_len; if (bytes < 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to receive length header from server."); return MONGOC_ASYNC_CMD_ERROR; } if (bytes == 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Server closed connection."); return MONGOC_ASYNC_CMD_ERROR; } acmd->bytes_to_read -= bytes; if (!acmd->bytes_to_read) { memcpy (&msg_len, acmd->buffer.data, 4); msg_len = BSON_UINT32_FROM_LE (msg_len); if ((msg_len < 16) || (msg_len > MONGOC_DEFAULT_MAX_MSG_SIZE)) { bson_set_error (&acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply from server."); return MONGOC_ASYNC_CMD_ERROR; } acmd->bytes_to_read = msg_len - 4; acmd->state = MONGOC_ASYNC_CMD_RECV_RPC; return _mongoc_async_cmd_phase_recv_rpc (acmd); } return MONGOC_ASYNC_CMD_IN_PROGRESS; } mongoc_async_cmd_result_t _mongoc_async_cmd_phase_recv_rpc (mongoc_async_cmd_t *acmd) { ssize_t bytes = _mongoc_buffer_try_append_from_stream (&acmd->buffer, acmd->stream, acmd->bytes_to_read, 0, &acmd->error); if (bytes < 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to receive rpc bytes from server."); return MONGOC_ASYNC_CMD_ERROR; } if (bytes == 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Server closed connection."); return MONGOC_ASYNC_CMD_ERROR; } acmd->bytes_to_read -= bytes; if (!acmd->bytes_to_read) { if (!_mongoc_rpc_scatter (&acmd->rpc, acmd->buffer.data, acmd->buffer.len)) { bson_set_error (&acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply from server."); return MONGOC_ASYNC_CMD_ERROR; } _mongoc_rpc_swab_from_le (&acmd->rpc); if (acmd->rpc.header.opcode != MONGOC_OPCODE_REPLY) { bson_set_error (&acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply from server."); return MONGOC_ASYNC_CMD_ERROR; } if (!_mongoc_rpc_reply_get_first (&acmd->rpc.reply, &acmd->reply)) { bson_set_error (&acmd->error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Failed to decode reply BSON document."); return MONGOC_ASYNC_CMD_ERROR; } acmd->reply_needs_cleanup = true; return MONGOC_ASYNC_CMD_SUCCESS; } return MONGOC_ASYNC_CMD_IN_PROGRESS; } libmongoc-1.3.1/src/mongoc/mongoc-async-private.h000066400000000000000000000050131264720626300217630ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_ASYNC_PRIVATE_H #define MONGOC_ASYNC_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-stream.h" BSON_BEGIN_DECLS struct _mongoc_async_cmd; typedef struct _mongoc_async { struct _mongoc_async_cmd *cmds; size_t ncmds; uint32_t request_id; } mongoc_async_t; typedef enum { MONGOC_ASYNC_CMD_IN_PROGRESS, MONGOC_ASYNC_CMD_SUCCESS, MONGOC_ASYNC_CMD_ERROR, MONGOC_ASYNC_CMD_TIMEOUT, } mongoc_async_cmd_result_t; typedef void (*mongoc_async_cmd_cb_t)(mongoc_async_cmd_result_t result, const bson_t *bson, int64_t rtt_msec, void *data, bson_error_t *error); typedef int (*mongoc_async_cmd_setup_t)(mongoc_stream_t *stream, int *events, void *ctx, int32_t timeout_msec, bson_error_t *error); mongoc_async_t * mongoc_async_new (); void mongoc_async_destroy (mongoc_async_t *async); bool mongoc_async_run (mongoc_async_t *async, int32_t timeout_msec); struct _mongoc_async_cmd * mongoc_async_cmd (mongoc_async_t *async, mongoc_stream_t *stream, mongoc_async_cmd_setup_t setup, void *setup_ctx, const char *dbname, const bson_t *cmd, mongoc_async_cmd_cb_t cb, void *cb_data, int32_t timeout_msec); BSON_END_DECLS #endif /* MONGOC_ASYNC_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-async.c000066400000000000000000000100401264720626300203020ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-async-private.h" #include "mongoc-async-cmd-private.h" #include "utlist.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "async" mongoc_async_cmd_t * mongoc_async_cmd (mongoc_async_t *async, mongoc_stream_t *stream, mongoc_async_cmd_setup_t setup, void *setup_ctx, const char *dbname, const bson_t *cmd, mongoc_async_cmd_cb_t cb, void *cb_data, int32_t timeout_msec) { return mongoc_async_cmd_new (async, stream, setup, setup_ctx, dbname, cmd, cb, cb_data, timeout_msec); } mongoc_async_t * mongoc_async_new () { mongoc_async_t *async = (mongoc_async_t *)bson_malloc0 (sizeof (*async)); return async; } void mongoc_async_destroy (mongoc_async_t *async) { mongoc_async_cmd_t *acmd, *tmp; DL_FOREACH_SAFE (async->cmds, acmd, tmp) { mongoc_async_cmd_destroy (acmd); } bson_free (async); } bool mongoc_async_run (mongoc_async_t *async, int32_t timeout_msec) { mongoc_async_cmd_t *acmd, *tmp; mongoc_stream_poll_t *poller = NULL; int i; ssize_t nactive = 0; int64_t now; int64_t expire_at = 0; size_t poll_size = 0; for (;;) { now = bson_get_monotonic_time (); if (expire_at == 0) { if (timeout_msec >= 0) { expire_at = now + ((int64_t) timeout_msec * 1000); } else { expire_at = -1; } } else if (timeout_msec >= 0) { timeout_msec = (expire_at - now) / 1000; } if (now > expire_at) { break; } DL_FOREACH_SAFE (async->cmds, acmd, tmp) { /* async commands are sorted by expire_at */ if (now > acmd->expire_at) { acmd->cb (MONGOC_ASYNC_CMD_TIMEOUT, NULL, (now - acmd->start_time), acmd->data, &acmd->error); mongoc_async_cmd_destroy (acmd); } else { break; } } if (!async->ncmds) { break; } if (poll_size < async->ncmds) { poller = (mongoc_stream_poll_t *)bson_realloc (poller, sizeof (*poller) * async->ncmds); poll_size = async->ncmds; } i = 0; DL_FOREACH (async->cmds, acmd) { poller[i].stream = acmd->stream; poller[i].events = acmd->events; poller[i].revents = 0; i++; } if (timeout_msec >= 0) { timeout_msec = BSON_MIN (timeout_msec, (async->cmds->expire_at - now) / 1000); } else { timeout_msec = (async->cmds->expire_at - now) / 1000; } nactive = mongoc_stream_poll (poller, async->ncmds, timeout_msec); if (nactive) { i = 0; DL_FOREACH_SAFE (async->cmds, acmd, tmp) { if (poller[i].revents & (POLLERR | POLLHUP)) { acmd->state = MONGOC_ASYNC_CMD_ERROR_STATE; } if (acmd->state == MONGOC_ASYNC_CMD_ERROR_STATE || (poller[i].revents & poller[i].events)) { mongoc_async_cmd_run (acmd); nactive--; if (!nactive) { break; } } i++; } } } if (poll_size) { bson_free (poller); } return async->ncmds; } libmongoc-1.3.1/src/mongoc/mongoc-b64-private.h000066400000000000000000000023041264720626300212410ustar00rootroot00000000000000/* * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_B64_PRIVATE_H #define MONGOC_B64_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-config.h" int mongoc_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize); void mongoc_b64_initialize_rmap (void); #ifdef MONGOC_ENABLE_SSL int mongoc_b64_pton (char const *src, uint8_t *target, size_t targsize); #endif #endif /* MONGOC_B64_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-b64.c000066400000000000000000000405051264720626300175710ustar00rootroot00000000000000/* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include "mongoc-b64-private.h" #define Assert(Cond) if (!(Cond)) abort () static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) * The following encoding technique is taken from RFC 1521 by Borenstein * and Freed. It is reproduced here in a slightly edited form for * convenience. * * A 65-character subset of US-ASCII is used, enabling 6 bits to be * represented per printable character. (The extra 65th character, "=", * is used to signify a special processing function.) * * The encoding process represents 24-bit groups of input bits as output * strings of 4 encoded characters. Proceeding from left to right, a * 24-bit input group is formed by concatenating 3 8-bit input groups. * These 24 bits are then treated as 4 concatenated 6-bit groups, each * of which is translated into a single digit in the base64 alphabet. * * Each 6-bit group is used as an index into an array of 64 printable * characters. The character referenced by the index is placed in the * output string. * * Table 1: The Base64 Alphabet * * Value Encoding Value Encoding Value Encoding Value Encoding * 0 A 17 R 34 i 51 z * 1 B 18 S 35 j 52 0 * 2 C 19 T 36 k 53 1 * 3 D 20 U 37 l 54 2 * 4 E 21 V 38 m 55 3 * 5 F 22 W 39 n 56 4 * 6 G 23 X 40 o 57 5 * 7 H 24 Y 41 p 58 6 * 8 I 25 Z 42 q 59 7 * 9 J 26 a 43 r 60 8 * 10 K 27 b 44 s 61 9 * 11 L 28 c 45 t 62 + * 12 M 29 d 46 u 63 / * 13 N 30 e 47 v * 14 O 31 f 48 w (pad) = * 15 P 32 g 49 x * 16 Q 33 h 50 y * * Special processing is performed if fewer than 24 bits are available * at the end of the data being encoded. A full encoding quantum is * always completed at the end of a quantity. When fewer than 24 input * bits are available in an input group, zero bits are added (on the * right) to form an integral number of 6-bit groups. Padding at the * end of the data is performed using the '=' character. * * Since all base64 input is an integral number of octets, only the * following cases can arise: * * (1) the final quantum of encoding input is an integral * multiple of 24 bits; here, the final unit of encoded * output will be an integral multiple of 4 characters * with no "=" padding, * (2) the final quantum of encoding input is exactly 8 bits; * here, the final unit of encoded output will be two * characters followed by two "=" padding characters, or * (3) the final quantum of encoding input is exactly 16 bits; * here, the final unit of encoded output will be three * characters followed by one "=" padding character. */ int mongoc_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; uint8_t input[3]; uint8_t output[4]; size_t i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; Assert (output[0] < 64); Assert (output[1] < 64); Assert (output[2] < 64); Assert (output[3] < 64); if (datalength + 4 > targsize) { return -1; } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) { input[i] = *src++; } output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); Assert (output[0] < 64); Assert (output[1] < 64); Assert (output[2] < 64); if (datalength + 4 > targsize) { return -1; } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) { target[datalength++] = Pad64; } else{ target[datalength++] = Base64[output[2]]; } target[datalength++] = Pad64; } if (datalength >= targsize) { return -1; } target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (int)datalength; } #ifdef MONGOC_ENABLE_SSL /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ static int mongoc_b64rmap_initialized = 0; static uint8_t mongoc_b64rmap[256]; static const uint8_t mongoc_b64rmap_special = 0xf0; static const uint8_t mongoc_b64rmap_end = 0xfd; static const uint8_t mongoc_b64rmap_space = 0xfe; static const uint8_t mongoc_b64rmap_invalid = 0xff; /** * Initializing the reverse map is not thread safe. * Which is fine for NSD. For now... **/ void mongoc_b64_initialize_rmap (void) { int i; unsigned char ch; /* Null: end of string, stop parsing */ mongoc_b64rmap[0] = mongoc_b64rmap_end; for (i = 1; i < 256; ++i) { ch = (unsigned char)i; /* Whitespaces */ if (isspace(ch)) mongoc_b64rmap[i] = mongoc_b64rmap_space; /* Padding: stop parsing */ else if (ch == Pad64) mongoc_b64rmap[i] = mongoc_b64rmap_end; /* Non-base64 char */ else mongoc_b64rmap[i] = mongoc_b64rmap_invalid; } /* Fill reverse mapping for base64 chars */ for (i = 0; Base64[i] != '\0'; ++i) mongoc_b64rmap[(uint8_t)Base64[i]] = i; mongoc_b64rmap_initialized = 1; } static int mongoc_b64_pton_do(char const *src, uint8_t *target, size_t targsize) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = mongoc_b64rmap[ch]; if (ofs >= mongoc_b64rmap_special) { /* Ignore whitespaces */ if (ofs == mongoc_b64rmap_space) continue; /* End of base64 characters */ if (ofs == mongoc_b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: if ((size_t)tarindex >= targsize) return (-1); target[tarindex] = ofs << 2; state = 1; break; case 1: if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 4; target[tarindex+1] = (ofs & 0x0f) << 4 ; tarindex++; state = 2; break; case 2: if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 2; target[tarindex+1] = (ofs & 0x03) << 6; tarindex++; state = 3; break; case 3: if ((size_t)tarindex >= targsize) return (-1); target[tarindex] |= ofs; tarindex++; state = 0; break; default: abort(); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void)NULL; ch != '\0'; ch = *src++) if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void)NULL; ch != '\0'; ch = *src++) if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target[tarindex] != 0) return (-1); default: break; } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } static int mongoc_b64_pton_len(char const *src) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = mongoc_b64rmap[ch]; if (ofs >= mongoc_b64rmap_special) { /* Ignore whitespaces */ if (ofs == mongoc_b64rmap_space) continue; /* End of base64 characters */ if (ofs == mongoc_b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: state = 1; break; case 1: tarindex++; state = 2; break; case 2: tarindex++; state = 3; break; case 3: tarindex++; state = 0; break; default: abort(); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void)NULL; ch != '\0'; ch = *src++) if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void)NULL; ch != '\0'; ch = *src++) if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) return (-1); default: break; } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } int mongoc_b64_pton(char const *src, uint8_t *target, size_t targsize) { if (!mongoc_b64rmap_initialized) mongoc_b64_initialize_rmap (); if (target) return mongoc_b64_pton_do (src, target, targsize); else return mongoc_b64_pton_len (src); } #endif /* MONGOC_ENABLE_SSL */ libmongoc-1.3.1/src/mongoc/mongoc-buffer-private.h000066400000000000000000000046251264720626300221270ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_BUFFER_PRIVATE_H #define MONGOC_BUFFER_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-stream.h" BSON_BEGIN_DECLS typedef struct _mongoc_buffer_t mongoc_buffer_t; struct _mongoc_buffer_t { uint8_t *data; size_t datalen; off_t off; size_t len; bson_realloc_func realloc_func; void *realloc_data; }; void _mongoc_buffer_init (mongoc_buffer_t *buffer, uint8_t *buf, size_t buflen, bson_realloc_func realloc_func, void *realloc_data); bool _mongoc_buffer_append_from_stream (mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t size, int32_t timeout_msec, bson_error_t *error); ssize_t _mongoc_buffer_try_append_from_stream (mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t size, int32_t timeout_msec, bson_error_t *error); ssize_t _mongoc_buffer_fill (mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t min_bytes, int32_t timeout_msec, bson_error_t *error); void _mongoc_buffer_destroy (mongoc_buffer_t *buffer); void _mongoc_buffer_clear (mongoc_buffer_t *buffer, bool zero); BSON_END_DECLS #endif /* MONGOC_BUFFER_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-buffer.c000066400000000000000000000216301264720626300204450ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "mongoc-error.h" #include "mongoc-buffer-private.h" #include "mongoc-trace.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "buffer" #ifndef MONGOC_BUFFER_DEFAULT_SIZE # define MONGOC_BUFFER_DEFAULT_SIZE 1024 #endif #define SPACE_FOR(_b, _sz) (((ssize_t)(_b)->datalen - (ssize_t)(_b)->off - (ssize_t)(_b)->len) >= (ssize_t)(_sz)) /** * _mongoc_buffer_init: * @buffer: A mongoc_buffer_t to initialize. * @buf: A data buffer to attach to @buffer. * @buflen: The size of @buflen. * @realloc_func: A function to resize @buf. * * Initializes @buffer for use. If additional space is needed by @buffer, then * @realloc_func will be called to resize @buf. * * @buffer takes ownership of @buf and will realloc it to zero bytes when * cleaning up the data structure. */ void _mongoc_buffer_init (mongoc_buffer_t *buffer, uint8_t *buf, size_t buflen, bson_realloc_func realloc_func, void *realloc_data) { BSON_ASSERT (buffer); BSON_ASSERT (buflen || !buf); if (!realloc_func) { realloc_func = bson_realloc_ctx; } if (!buflen) { buflen = MONGOC_BUFFER_DEFAULT_SIZE; } if (!buf) { buf = (uint8_t *)realloc_func (NULL, buflen, NULL); } memset (buffer, 0, sizeof *buffer); buffer->data = buf; buffer->datalen = buflen; buffer->len = 0; buffer->off = 0; buffer->realloc_func = realloc_func; buffer->realloc_data = realloc_data; } /** * _mongoc_buffer_destroy: * @buffer: A mongoc_buffer_t. * * Cleanup after @buffer and release any allocated resources. */ void _mongoc_buffer_destroy (mongoc_buffer_t *buffer) { BSON_ASSERT (buffer); if (buffer->data && buffer->realloc_func) { buffer->realloc_func (buffer->data, 0, buffer->realloc_data); } memset(buffer, 0, sizeof *buffer); } /** * _mongoc_buffer_clear: * @buffer: A mongoc_buffer_t. * @zero: If the memory should be zeroed. * * Clears a buffers contents and resets it to initial state. You can request * that the memory is zeroed, which might be useful if you know the contents * contain security related information. */ void _mongoc_buffer_clear (mongoc_buffer_t *buffer, bool zero) { BSON_ASSERT (buffer); if (zero) { memset(buffer->data, 0, buffer->datalen); } buffer->off = 0; buffer->len = 0; } /** * mongoc_buffer_append_from_stream: * @buffer; A mongoc_buffer_t. * @stream: The stream to read from. * @size: The number of bytes to read. * @timeout_msec: The number of milliseconds to wait or -1 for the default * @error: A location for a bson_error_t, or NULL. * * Reads from stream @size bytes and stores them in @buffer. This can be used * in conjunction with reading RPCs from a stream. You read from the stream * into this buffer and then scatter the buffer into the RPC. * * Returns: true if successful; otherwise false and @error is set. */ bool _mongoc_buffer_append_from_stream (mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t size, int32_t timeout_msec, bson_error_t *error) { uint8_t *buf; ssize_t ret; ENTRY; BSON_ASSERT (buffer); BSON_ASSERT (stream); BSON_ASSERT (size); BSON_ASSERT (buffer->datalen); BSON_ASSERT ((buffer->datalen + size) < INT_MAX); if (!SPACE_FOR (buffer, size)) { if (buffer->len) { memmove(&buffer->data[0], &buffer->data[buffer->off], buffer->len); } buffer->off = 0; if (!SPACE_FOR (buffer, size)) { buffer->datalen = bson_next_power_of_two (size + buffer->len + buffer->off); buffer->data = (uint8_t *)buffer->realloc_func (buffer->data, buffer->datalen, NULL); } } buf = &buffer->data[buffer->off + buffer->len]; BSON_ASSERT ((buffer->off + buffer->len + size) <= buffer->datalen); ret = mongoc_stream_read (stream, buf, size, size, timeout_msec); if (ret != size) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to read %"PRIu64" bytes from socket within %d milliseconds.", (uint64_t)size, (int)timeout_msec); RETURN (false); } buffer->len += ret; RETURN (true); } /** * _mongoc_buffer_fill: * @buffer: A mongoc_buffer_t. * @stream: A stream to read from. * @min_bytes: The minumum number of bytes to read. * @error: A location for a bson_error_t or NULL. * * Attempts to fill the entire buffer, or at least @min_bytes. * * Returns: The number of buffered bytes, or -1 on failure. */ ssize_t _mongoc_buffer_fill (mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t min_bytes, int32_t timeout_msec, bson_error_t *error) { ssize_t ret; size_t avail_bytes; ENTRY; BSON_ASSERT (buffer); BSON_ASSERT (stream); BSON_ASSERT (buffer->data); BSON_ASSERT (buffer->datalen); if (min_bytes <= buffer->len) { RETURN (buffer->len); } min_bytes -= buffer->len; if (buffer->len) { memmove (&buffer->data[0], &buffer->data[buffer->off], buffer->len); } buffer->off = 0; if (!SPACE_FOR (buffer, min_bytes)) { buffer->datalen = bson_next_power_of_two (buffer->len + min_bytes); buffer->data = (uint8_t *)buffer->realloc_func (buffer->data, buffer->datalen, buffer->realloc_data); } avail_bytes = buffer->datalen - buffer->len; ret = mongoc_stream_read (stream, &buffer->data[buffer->off + buffer->len], avail_bytes, min_bytes, timeout_msec); if (ret == -1) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to buffer %u bytes within %d milliseconds.", (unsigned)min_bytes, (int)timeout_msec); RETURN (-1); } buffer->len += ret; if (buffer->len < min_bytes) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Could only buffer %u of %u bytes in %d milliseconds.", (unsigned)buffer->len, (unsigned)min_bytes, (int)timeout_msec); RETURN (-1); } RETURN (buffer->len); } /** * mongoc_buffer_try_append_from_stream: * @buffer; A mongoc_buffer_t. * @stream: The stream to read from. * @size: The number of bytes to read. * @timeout_msec: The number of milliseconds to wait or -1 for the default * @error: A location for a bson_error_t, or NULL. * * Reads from stream @size bytes and stores them in @buffer. This can be used * in conjunction with reading RPCs from a stream. You read from the stream * into this buffer and then scatter the buffer into the RPC. * * Returns: bytes read if successful; otherwise -1 and @error is set. */ ssize_t _mongoc_buffer_try_append_from_stream (mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t size, int32_t timeout_msec, bson_error_t *error) { uint8_t *buf; ssize_t ret; ENTRY; BSON_ASSERT (buffer); BSON_ASSERT (stream); BSON_ASSERT (size); BSON_ASSERT (buffer->datalen); BSON_ASSERT ((buffer->datalen + size) < INT_MAX); if (!SPACE_FOR (buffer, size)) { if (buffer->len) { memmove(&buffer->data[0], &buffer->data[buffer->off], buffer->len); } buffer->off = 0; if (!SPACE_FOR (buffer, size)) { buffer->datalen = bson_next_power_of_two (size + buffer->len + buffer->off); buffer->data = (uint8_t *)buffer->realloc_func (buffer->data, buffer->datalen, NULL); } } buf = &buffer->data[buffer->off + buffer->len]; BSON_ASSERT ((buffer->off + buffer->len + size) <= buffer->datalen); ret = mongoc_stream_read (stream, buf, size, 0, timeout_msec); if (ret > 0) { buffer->len += ret; } RETURN (ret); } libmongoc-1.3.1/src/mongoc/mongoc-bulk-operation-private.h000066400000000000000000000035501264720626300236050ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_BULK_OPERATION_PRIVATE_H #define MONGOC_BULK_OPERATION_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include "mongoc-array-private.h" #include "mongoc-client.h" #include "mongoc-write-command-private.h" BSON_BEGIN_DECLS struct _mongoc_bulk_operation_t { char *database; char *collection; mongoc_client_t *client; mongoc_write_concern_t *write_concern; mongoc_bulk_write_flags_t flags; uint32_t hint; mongoc_array_t commands; mongoc_write_result_t result; bool executed; }; mongoc_bulk_operation_t *_mongoc_bulk_operation_new (mongoc_client_t *client, const char *database, const char *collection, mongoc_bulk_write_flags_t flags, const mongoc_write_concern_t *write_concern); BSON_END_DECLS #endif /* MONGOC_BULK_OPERATION_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-bulk-operation.c000066400000000000000000000361061264720626300221330ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-bulk-operation.h" #include "mongoc-bulk-operation-private.h" #include "mongoc-client-private.h" #include "mongoc-error.h" #include "mongoc-trace.h" #include "mongoc-write-concern-private.h" /* * This is the implementation of both write commands and bulk write commands. * They are all implemented as one contiguous set since we'd like to cut down * on code duplication here. * * This implementation is currently naive. * * Some interesting optimizations might be: * * - If unordered mode, send operations as we get them instead of waiting * for execute() to be called. This could save us memcpy()'s too. * - If there is no acknowledgement desired, keep a count of how many * replies we need and ask the socket layer to skip that many bytes * when reading. * - Try to use iovec to send write commands with subdocuments rather than * copying them into the write command document. */ mongoc_bulk_operation_t * mongoc_bulk_operation_new (bool ordered) { mongoc_bulk_operation_t *bulk; bulk = (mongoc_bulk_operation_t *)bson_malloc0 (sizeof *bulk); bulk->flags.bypass_document_validation = MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT; bulk->flags.ordered = ordered; bulk->hint = 0; _mongoc_array_init (&bulk->commands, sizeof (mongoc_write_command_t)); return bulk; } mongoc_bulk_operation_t * _mongoc_bulk_operation_new (mongoc_client_t *client, /* IN */ const char *database, /* IN */ const char *collection, /* IN */ mongoc_bulk_write_flags_t flags, /* IN */ const mongoc_write_concern_t *write_concern) /* IN */ { mongoc_bulk_operation_t *bulk; BSON_ASSERT (client); BSON_ASSERT (collection); bulk = mongoc_bulk_operation_new (flags.ordered); bulk->client = client; bulk->database = bson_strdup (database); bulk->collection = bson_strdup (collection); bulk->write_concern = mongoc_write_concern_copy (write_concern); bulk->executed = false; bulk->flags = flags; return bulk; } void mongoc_bulk_operation_destroy (mongoc_bulk_operation_t *bulk) /* IN */ { mongoc_write_command_t *command; int i; if (bulk) { for (i = 0; i < bulk->commands.len; i++) { command = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, i); _mongoc_write_command_destroy (command); } bson_free (bulk->database); bson_free (bulk->collection); mongoc_write_concern_destroy (bulk->write_concern); _mongoc_array_destroy (&bulk->commands); if (bulk->executed) { _mongoc_write_result_destroy (&bulk->result); } bson_free (bulk); } } void mongoc_bulk_operation_remove (mongoc_bulk_operation_t *bulk, /* IN */ const bson_t *selector) /* IN */ { mongoc_write_command_t command = { 0 }; mongoc_write_command_t *last; ENTRY; BSON_ASSERT (bulk); BSON_ASSERT (selector); if (bulk->commands.len) { last = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1); if ((last->type == MONGOC_WRITE_COMMAND_DELETE) && last->u.delete_.multi) { _mongoc_write_command_delete_append (last, selector); EXIT; } } _mongoc_write_command_init_delete (&command, selector, true, bulk->flags); _mongoc_array_append_val (&bulk->commands, command); EXIT; } void mongoc_bulk_operation_remove_one (mongoc_bulk_operation_t *bulk, /* IN */ const bson_t *selector) /* IN */ { mongoc_write_command_t command = { 0 }; mongoc_write_command_t *last; ENTRY; BSON_ASSERT (bulk); BSON_ASSERT (selector); if (bulk->commands.len) { last = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1); if ((last->type == MONGOC_WRITE_COMMAND_DELETE) && !last->u.delete_.multi) { _mongoc_write_command_delete_append (last, selector); EXIT; } } _mongoc_write_command_init_delete (&command, selector, false, bulk->flags); _mongoc_array_append_val (&bulk->commands, command); EXIT; } void mongoc_bulk_operation_delete (mongoc_bulk_operation_t *bulk, const bson_t *selector) { ENTRY; mongoc_bulk_operation_remove (bulk, selector); EXIT; } void mongoc_bulk_operation_delete_one (mongoc_bulk_operation_t *bulk, const bson_t *selector) { ENTRY; mongoc_bulk_operation_remove_one (bulk, selector); EXIT; } void mongoc_bulk_operation_insert (mongoc_bulk_operation_t *bulk, const bson_t *document) { mongoc_write_command_t command = { 0 }; mongoc_write_command_t *last; ENTRY; BSON_ASSERT (bulk); BSON_ASSERT (document); if (bulk->commands.len) { last = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1); if (last->type == MONGOC_WRITE_COMMAND_INSERT) { _mongoc_write_command_insert_append (last, document); EXIT; } } _mongoc_write_command_init_insert ( &command, document, bulk->flags, !_mongoc_write_concern_needs_gle (bulk->write_concern)); _mongoc_array_append_val (&bulk->commands, command); EXIT; } void mongoc_bulk_operation_replace_one (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert) { mongoc_write_command_t command = { 0 }; size_t err_off; mongoc_write_command_t *last; int flags = BSON_VALIDATE_DOT_KEYS|BSON_VALIDATE_DOLLAR_KEYS; BSON_ASSERT (bulk); BSON_ASSERT (selector); BSON_ASSERT (document); ENTRY; if (!bson_validate (document, (bson_validate_flags_t)flags, &err_off)) { MONGOC_WARNING ("%s(): replacement document may not contain " "$ or . in keys. Ignoring document.", BSON_FUNC); EXIT; } if (bulk->commands.len) { last = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1); if (last->type == MONGOC_WRITE_COMMAND_UPDATE) { _mongoc_write_command_update_append (last, selector, document, upsert, false); EXIT; } } _mongoc_write_command_init_update (&command, selector, document, upsert, false, bulk->flags); _mongoc_array_append_val (&bulk->commands, command); EXIT; } void mongoc_bulk_operation_update (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert) { bool multi = true; mongoc_write_command_t command = { 0 }; bson_iter_t iter; mongoc_write_command_t *last; BSON_ASSERT (bulk); BSON_ASSERT (selector); BSON_ASSERT (document); ENTRY; if (bson_iter_init (&iter, document)) { while (bson_iter_next (&iter)) { if (!strchr (bson_iter_key (&iter), '$')) { MONGOC_WARNING ("%s(): update only works with $ operators.", BSON_FUNC); EXIT; } } } if (bulk->commands.len) { last = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1); if (last->type == MONGOC_WRITE_COMMAND_UPDATE) { _mongoc_write_command_update_append (last, selector, document, upsert, multi); EXIT; } } _mongoc_write_command_init_update (&command, selector, document, upsert, multi, bulk->flags); _mongoc_array_append_val (&bulk->commands, command); EXIT; } void mongoc_bulk_operation_update_one (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert) { mongoc_write_command_t command = { 0 }; bson_iter_t iter; mongoc_write_command_t *last; BSON_ASSERT (bulk); BSON_ASSERT (selector); BSON_ASSERT (document); ENTRY; if (bson_iter_init (&iter, document)) { while (bson_iter_next (&iter)) { if (!strchr (bson_iter_key (&iter), '$')) { MONGOC_WARNING ("%s(): update_one only works with $ operators.", BSON_FUNC); EXIT; } } } if (bulk->commands.len) { last = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1); if (last->type == MONGOC_WRITE_COMMAND_UPDATE) { _mongoc_write_command_update_append (last, selector, document, upsert, false); EXIT; } } _mongoc_write_command_init_update (&command, selector, document, upsert, false, bulk->flags); _mongoc_array_append_val (&bulk->commands, command); EXIT; } uint32_t mongoc_bulk_operation_execute (mongoc_bulk_operation_t *bulk, /* IN */ bson_t *reply, /* OUT */ bson_error_t *error) /* OUT */ { mongoc_cluster_t *cluster; mongoc_write_command_t *command; mongoc_server_stream_t *server_stream; bool ret; uint32_t offset = 0; int i; ENTRY; BSON_ASSERT (bulk); cluster = &bulk->client->cluster; if (bulk->executed) { _mongoc_write_result_destroy (&bulk->result); } _mongoc_write_result_init (&bulk->result); bulk->executed = true; if (!bulk->client) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "mongoc_bulk_operation_execute() requires a client " "and one has not been set."); RETURN (false); } else if (!bulk->database) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "mongoc_bulk_operation_execute() requires a database " "and one has not been set."); RETURN (false); } else if (!bulk->collection) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "mongoc_bulk_operation_execute() requires a collection " "and one has not been set."); RETURN (false); } if (reply) { bson_init (reply); } if (!bulk->commands.len) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot do an empty bulk write"); RETURN (false); } if (bulk->hint) { server_stream = mongoc_cluster_stream_for_server (cluster, bulk->hint, true /* reconnect_ok */, error); } else { server_stream = mongoc_cluster_stream_for_writes (cluster, error); } if (!server_stream) { RETURN (false); } for (i = 0; i < bulk->commands.len; i++) { command = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, i); _mongoc_write_command_execute (command, bulk->client, server_stream, bulk->database, bulk->collection, bulk->write_concern, offset, &bulk->result); bulk->hint = command->hint; if (bulk->result.failed && bulk->flags.ordered) { GOTO (cleanup); } offset += command->n_documents; } cleanup: ret = _mongoc_write_result_complete (&bulk->result, reply, error); mongoc_server_stream_cleanup (server_stream); RETURN (ret ? bulk->hint : 0); } void mongoc_bulk_operation_set_write_concern (mongoc_bulk_operation_t *bulk, const mongoc_write_concern_t *write_concern) { BSON_ASSERT (bulk); if (bulk->write_concern) { mongoc_write_concern_destroy (bulk->write_concern); } if (write_concern) { bulk->write_concern = mongoc_write_concern_copy (write_concern); } else { bulk->write_concern = mongoc_write_concern_new (); } } const mongoc_write_concern_t * mongoc_bulk_operation_get_write_concern (const mongoc_bulk_operation_t *bulk) { BSON_ASSERT (bulk); return bulk->write_concern; } void mongoc_bulk_operation_set_database (mongoc_bulk_operation_t *bulk, const char *database) { BSON_ASSERT (bulk); if (bulk->database) { bson_free (bulk->database); } bulk->database = bson_strdup (database); } void mongoc_bulk_operation_set_collection (mongoc_bulk_operation_t *bulk, const char *collection) { BSON_ASSERT (bulk); if (bulk->collection) { bson_free (bulk->collection); } bulk->collection = bson_strdup (collection); } void mongoc_bulk_operation_set_client (mongoc_bulk_operation_t *bulk, void *client) { BSON_ASSERT (bulk); bulk->client = (mongoc_client_t *)client; } void mongoc_bulk_operation_set_hint (mongoc_bulk_operation_t *bulk, uint32_t hint) { BSON_ASSERT (bulk); bulk->hint = hint; } void mongoc_bulk_operation_set_bypass_document_validation (mongoc_bulk_operation_t *bulk, bool bypass) { BSON_ASSERT (bulk); bulk->flags.bypass_document_validation = bypass ? MONGOC_BYPASS_DOCUMENT_VALIDATION_TRUE : MONGOC_BYPASS_DOCUMENT_VALIDATION_FALSE; } libmongoc-1.3.1/src/mongoc/mongoc-bulk-operation.h000066400000000000000000000114271264720626300221370ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_BULK_OPERATION_H #define MONGOC_BULK_OPERATION_H #include #include "mongoc-write-concern.h" #define MONGOC_BULK_WRITE_FLAGS_INIT { true, MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT } BSON_BEGIN_DECLS typedef struct _mongoc_bulk_operation_t mongoc_bulk_operation_t; typedef struct _mongoc_bulk_write_flags_t mongoc_bulk_write_flags_t; void mongoc_bulk_operation_destroy (mongoc_bulk_operation_t *bulk); uint32_t mongoc_bulk_operation_execute (mongoc_bulk_operation_t *bulk, bson_t *reply, bson_error_t *error); void mongoc_bulk_operation_delete (mongoc_bulk_operation_t *bulk, const bson_t *selector) BSON_GNUC_DEPRECATED_FOR (mongoc_bulk_operation_remove); void mongoc_bulk_operation_delete_one (mongoc_bulk_operation_t *bulk, const bson_t *selector) BSON_GNUC_DEPRECATED_FOR (mongoc_bulk_operation_remove_one); void mongoc_bulk_operation_insert (mongoc_bulk_operation_t *bulk, const bson_t *document); void mongoc_bulk_operation_remove (mongoc_bulk_operation_t *bulk, const bson_t *selector); void mongoc_bulk_operation_remove_one (mongoc_bulk_operation_t *bulk, const bson_t *selector); void mongoc_bulk_operation_replace_one (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert); void mongoc_bulk_operation_update (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert); void mongoc_bulk_operation_update_one (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert); void mongoc_bulk_operation_set_bypass_document_validation (mongoc_bulk_operation_t *bulk, bool bypass); /* * The following functions are really only useful by language bindings and * those wanting to replay a bulk operation to a number of clients or * collections. */ mongoc_bulk_operation_t *mongoc_bulk_operation_new (bool ordered); void mongoc_bulk_operation_set_write_concern (mongoc_bulk_operation_t *bulk, const mongoc_write_concern_t *write_concern); void mongoc_bulk_operation_set_database (mongoc_bulk_operation_t *bulk, const char *database); void mongoc_bulk_operation_set_collection (mongoc_bulk_operation_t *bulk, const char *collection); void mongoc_bulk_operation_set_client (mongoc_bulk_operation_t *bulk, void *client); void mongoc_bulk_operation_set_hint (mongoc_bulk_operation_t *bulk, uint32_t hint); const mongoc_write_concern_t *mongoc_bulk_operation_get_write_concern (const mongoc_bulk_operation_t *bulk); BSON_END_DECLS #endif /* MONGOC_BULK_OPERATION_H */ libmongoc-1.3.1/src/mongoc/mongoc-client-pool-private.h000066400000000000000000000017471264720626300231050ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CLIENT_POOL_PRIVATE_H #define MONGOC_CLIENT_POOL_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-client-pool.h" BSON_BEGIN_DECLS size_t mongoc_client_pool_get_size(mongoc_client_pool_t *pool); BSON_END_DECLS #endif /* MONGOC_CLIENT_POOL_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-client-pool.c000066400000000000000000000143041264720626300214210ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-counters-private.h" #include "mongoc-client-pool-private.h" #include "mongoc-client-pool.h" #include "mongoc-client-private.h" #include "mongoc-queue-private.h" #include "mongoc-thread-private.h" #include "mongoc-topology-private.h" #include "mongoc-trace.h" struct _mongoc_client_pool_t { mongoc_mutex_t mutex; mongoc_cond_t cond; mongoc_queue_t queue; mongoc_topology_t *topology; mongoc_uri_t *uri; uint32_t min_pool_size; uint32_t max_pool_size; uint32_t size; #ifdef MONGOC_ENABLE_SSL bool ssl_opts_set; mongoc_ssl_opt_t ssl_opts; #endif }; #ifdef MONGOC_ENABLE_SSL void mongoc_client_pool_set_ssl_opts (mongoc_client_pool_t *pool, const mongoc_ssl_opt_t *opts) { BSON_ASSERT (pool); mongoc_mutex_lock (&pool->mutex); memset (&pool->ssl_opts, 0, sizeof pool->ssl_opts); pool->ssl_opts_set = false; if (opts) { memcpy (&pool->ssl_opts, opts, sizeof pool->ssl_opts); pool->ssl_opts_set = true; } mongoc_topology_scanner_set_ssl_opts (pool->topology->scanner, &pool->ssl_opts); mongoc_mutex_unlock (&pool->mutex); } #endif mongoc_client_pool_t * mongoc_client_pool_new (const mongoc_uri_t *uri) { mongoc_topology_t *topology; mongoc_client_pool_t *pool; const bson_t *b; bson_iter_t iter; ENTRY; BSON_ASSERT (uri); #ifndef MONGOC_ENABLE_SSL if (mongoc_uri_get_ssl (uri)) { MONGOC_ERROR ("Can't create SSL client pool," " SSL not enabled in this build."); return NULL; } #endif pool = (mongoc_client_pool_t *)bson_malloc0(sizeof *pool); mongoc_mutex_init(&pool->mutex); _mongoc_queue_init(&pool->queue); pool->uri = mongoc_uri_copy(uri); pool->min_pool_size = 0; pool->max_pool_size = 100; pool->size = 0; topology = mongoc_topology_new(uri, false); pool->topology = topology; b = mongoc_uri_get_options(pool->uri); if (bson_iter_init_find_case(&iter, b, "minpoolsize")) { if (BSON_ITER_HOLDS_INT32(&iter)) { pool->min_pool_size = BSON_MAX(0, bson_iter_int32(&iter)); } } if (bson_iter_init_find_case(&iter, b, "maxpoolsize")) { if (BSON_ITER_HOLDS_INT32(&iter)) { pool->max_pool_size = BSON_MAX(1, bson_iter_int32(&iter)); } } mongoc_counter_client_pools_active_inc(); RETURN(pool); } void mongoc_client_pool_destroy (mongoc_client_pool_t *pool) { mongoc_client_t *client; ENTRY; BSON_ASSERT (pool); while ((client = (mongoc_client_t *)_mongoc_queue_pop_head(&pool->queue))) { mongoc_client_destroy(client); } mongoc_topology_destroy (pool->topology); mongoc_uri_destroy(pool->uri); mongoc_mutex_destroy(&pool->mutex); mongoc_cond_destroy(&pool->cond); bson_free(pool); mongoc_counter_client_pools_active_dec(); mongoc_counter_client_pools_disposed_inc(); EXIT; } mongoc_client_t * mongoc_client_pool_pop (mongoc_client_pool_t *pool) { mongoc_client_t *client; ENTRY; BSON_ASSERT (pool); mongoc_mutex_lock(&pool->mutex); again: if (!(client = (mongoc_client_t *)_mongoc_queue_pop_head(&pool->queue))) { if (pool->size < pool->max_pool_size) { client = _mongoc_client_new_from_uri(pool->uri, pool->topology); #ifdef MONGOC_ENABLE_SSL if (pool->ssl_opts_set) { mongoc_client_set_ssl_opts (client, &pool->ssl_opts); } #endif pool->size++; } else { mongoc_cond_wait(&pool->cond, &pool->mutex); GOTO(again); } } mongoc_mutex_unlock(&pool->mutex); RETURN(client); } mongoc_client_t * mongoc_client_pool_try_pop (mongoc_client_pool_t *pool) { mongoc_client_t *client; ENTRY; BSON_ASSERT (pool); mongoc_mutex_lock(&pool->mutex); if (!(client = (mongoc_client_t *)_mongoc_queue_pop_head(&pool->queue))) { if (pool->size < pool->max_pool_size) { client = _mongoc_client_new_from_uri(pool->uri, pool->topology); #ifdef MONGOC_ENABLE_SSL if (pool->ssl_opts_set) { mongoc_client_set_ssl_opts (client, &pool->ssl_opts); } #endif pool->size++; } } mongoc_mutex_unlock(&pool->mutex); RETURN(client); } void mongoc_client_pool_push (mongoc_client_pool_t *pool, mongoc_client_t *client) { ENTRY; BSON_ASSERT (pool); BSON_ASSERT (client); mongoc_mutex_lock(&pool->mutex); if (pool->size > pool->min_pool_size) { mongoc_client_t *old_client; old_client = (mongoc_client_t *)_mongoc_queue_pop_head (&pool->queue); if (old_client) { mongoc_client_destroy (old_client); pool->size--; } } mongoc_mutex_unlock(&pool->mutex); mongoc_mutex_lock (&pool->mutex); _mongoc_queue_push_tail (&pool->queue, client); mongoc_cond_signal(&pool->cond); mongoc_mutex_unlock(&pool->mutex); EXIT; } size_t mongoc_client_pool_get_size (mongoc_client_pool_t *pool) { size_t size = 0; ENTRY; mongoc_mutex_lock (&pool->mutex); size = pool->size; mongoc_mutex_unlock (&pool->mutex); RETURN (size); } void mongoc_client_pool_max_size(mongoc_client_pool_t *pool, uint32_t max_pool_size) { ENTRY; mongoc_mutex_lock (&pool->mutex); pool->max_pool_size = max_pool_size; mongoc_mutex_unlock (&pool->mutex); EXIT; } void mongoc_client_pool_min_size(mongoc_client_pool_t *pool, uint32_t min_pool_size) { ENTRY; mongoc_mutex_lock (&pool->mutex); pool->min_pool_size = min_pool_size; mongoc_mutex_unlock (&pool->mutex); EXIT; } libmongoc-1.3.1/src/mongoc/mongoc-client-pool.h000066400000000000000000000040331264720626300214240ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CLIENT_POOL_H #define MONGOC_CLIENT_POOL_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-client.h" #include "mongoc-config.h" #ifdef MONGOC_ENABLE_SSL # include "mongoc-ssl.h" #endif #include "mongoc-uri.h" BSON_BEGIN_DECLS typedef struct _mongoc_client_pool_t mongoc_client_pool_t; mongoc_client_pool_t *mongoc_client_pool_new (const mongoc_uri_t *uri); void mongoc_client_pool_destroy (mongoc_client_pool_t *pool); mongoc_client_t *mongoc_client_pool_pop (mongoc_client_pool_t *pool); void mongoc_client_pool_push (mongoc_client_pool_t *pool, mongoc_client_t *client); mongoc_client_t *mongoc_client_pool_try_pop (mongoc_client_pool_t *pool); void mongoc_client_pool_max_size(mongoc_client_pool_t *pool, uint32_t max_pool_size); void mongoc_client_pool_min_size(mongoc_client_pool_t *pool, uint32_t min_pool_size); #ifdef MONGOC_ENABLE_SSL void mongoc_client_pool_set_ssl_opts (mongoc_client_pool_t *pool, const mongoc_ssl_opt_t *opts); #endif BSON_END_DECLS #endif /* MONGOC_CLIENT_POOL_H */ libmongoc-1.3.1/src/mongoc/mongoc-client-private.h000066400000000000000000000106641264720626300221340ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CLIENT_PRIVATE_H #define MONGOC_CLIENT_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-buffer-private.h" #include "mongoc-client.h" #include "mongoc-cluster-private.h" #include "mongoc-config.h" #include "mongoc-host-list.h" #include "mongoc-read-prefs.h" #include "mongoc-rpc-private.h" #include "mongoc-opcode.h" #ifdef MONGOC_ENABLE_SSL #include "mongoc-ssl.h" #endif #include "mongoc-stream.h" #include "mongoc-topology-private.h" #include "mongoc-write-concern.h" BSON_BEGIN_DECLS /* protocol versions this driver can speak */ #define WIRE_VERSION_MIN 0 #define WIRE_VERSION_MAX 4 /* first version that supported aggregation cursors */ #define WIRE_VERSION_AGG_CURSOR 1 /* first version that supported "insert", "update", "delete" commands */ #define WIRE_VERSION_WRITE_CMD 2 /* first version when SCRAM-SHA-1 replaced MONGODB-CR as default auth mech */ #define WIRE_VERSION_SCRAM_DEFAULT 3 /* first version that supported "find" and "getMore" commands */ #define WIRE_VERSION_FIND_CMD 4 /* first version with "killCursors" command */ #define WIRE_VERSION_KILLCURSORS_CMD 4 /* first version when findAndModify accepts writeConcern */ #define WIRE_VERSION_FAM_WRITE_CONCERN 4 /* first version to support readConcern */ #define WIRE_VERSION_READ_CONCERN 4 struct _mongoc_client_t { uint32_t request_id; mongoc_list_t *conns; mongoc_uri_t *uri; mongoc_cluster_t cluster; bool in_exhaust; mongoc_stream_initiator_t initiator; void *initiator_data; #ifdef MONGOC_ENABLE_SSL bool use_ssl; mongoc_ssl_opt_t ssl_opts; char *pem_subject; #endif mongoc_topology_t *topology; mongoc_read_prefs_t *read_prefs; mongoc_read_concern_t *read_concern; mongoc_write_concern_t *write_concern; }; mongoc_client_t * _mongoc_client_new_from_uri (const mongoc_uri_t *uri, mongoc_topology_t *topology); mongoc_stream_t * mongoc_client_default_stream_initiator (const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *user_data, bson_error_t *error); mongoc_stream_t * _mongoc_client_create_stream (mongoc_client_t *client, const mongoc_host_list_t *host, bson_error_t *error); bool _mongoc_client_recv (mongoc_client_t *client, mongoc_rpc_t *rpc, mongoc_buffer_t *buffer, mongoc_server_stream_t *server_stream, bson_error_t *error); bool _mongoc_client_recv_gle (mongoc_client_t *client, mongoc_server_stream_t *server_stream, bson_t **gle_doc, bson_error_t *error); void _mongoc_topology_background_thread_start (mongoc_topology_t *topology); void _mongoc_topology_background_thread_stop (mongoc_topology_t *topology); mongoc_server_description_t * _mongoc_client_get_server_description (mongoc_client_t *client, uint32_t server_id); void _mongoc_client_kill_cursor (mongoc_client_t *client, uint32_t server_id, int64_t cursor_id, const char *db, const char *collection); BSON_END_DECLS #endif /* MONGOC_CLIENT_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-client.c000066400000000000000000001221001264720626300204440ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #ifndef _WIN32 # include # include #endif #include "mongoc-cursor-array-private.h" #include "mongoc-client-private.h" #include "mongoc-collection-private.h" #include "mongoc-config.h" #include "mongoc-counters-private.h" #include "mongoc-database-private.h" #include "mongoc-gridfs-private.h" #include "mongoc-error.h" #include "mongoc-log.h" #include "mongoc-queue-private.h" #include "mongoc-socket.h" #include "mongoc-stream-buffered.h" #include "mongoc-stream-socket.h" #include "mongoc-thread-private.h" #include "mongoc-trace.h" #include "mongoc-uri-private.h" #include "mongoc-util-private.h" #ifdef MONGOC_ENABLE_SSL #include "mongoc-stream-tls.h" #include "mongoc-ssl-private.h" #endif #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "client" static void _mongoc_client_op_killcursors (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, int64_t cursor_id); static void _mongoc_client_killcursors_command (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, int64_t cursor_id, const char *db, const char *collection); /* *-------------------------------------------------------------------------- * * mongoc_client_connect_tcp -- * * Connect to a host using a TCP socket. * * This will be performed synchronously and return a mongoc_stream_t * that can be used to connect with the remote host. * * Returns: * A newly allocated mongoc_stream_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error is set if return value is NULL. * *-------------------------------------------------------------------------- */ static mongoc_stream_t * mongoc_client_connect_tcp (const mongoc_uri_t *uri, const mongoc_host_list_t *host, bson_error_t *error) { mongoc_socket_t *sock = NULL; struct addrinfo hints; struct addrinfo *result, *rp; int32_t connecttimeoutms; int64_t expire_at; char portstr [8]; int s; ENTRY; BSON_ASSERT (uri); BSON_ASSERT (host); connecttimeoutms = mongoc_uri_get_option_as_int32 ( uri, "connecttimeoutms", MONGOC_DEFAULT_CONNECTTIMEOUTMS); BSON_ASSERT (connecttimeoutms); expire_at = bson_get_monotonic_time () + (connecttimeoutms * 1000L); bson_snprintf (portstr, sizeof portstr, "%hu", host->port); memset (&hints, 0, sizeof hints); hints.ai_family = host->family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = 0; s = getaddrinfo (host->host, portstr, &hints, &result); if (s != 0) { mongoc_counter_dns_failure_inc (); bson_set_error(error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, "Failed to resolve %s", host->host); RETURN (NULL); } mongoc_counter_dns_success_inc (); for (rp = result; rp; rp = rp->ai_next) { /* * Create a new non-blocking socket. */ if (!(sock = mongoc_socket_new (rp->ai_family, rp->ai_socktype, rp->ai_protocol))) { continue; } /* * Try to connect to the peer. */ if (0 != mongoc_socket_connect (sock, rp->ai_addr, (socklen_t)rp->ai_addrlen, expire_at)) { char *errmsg; char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; char ip[255]; mongoc_socket_inet_ntop (rp, ip, sizeof ip); errmsg = bson_strerror_r ( mongoc_socket_errno (sock), errmsg_buf, sizeof errmsg_buf); MONGOC_WARNING ("Failed to connect to: %s:%d, error: %d, %s\n", ip, host->port, mongoc_socket_errno(sock), errmsg); mongoc_socket_destroy (sock); sock = NULL; continue; } break; } if (!sock) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "Failed to connect to target host: %s", host->host_and_port); freeaddrinfo (result); RETURN (NULL); } freeaddrinfo (result); return mongoc_stream_socket_new (sock); } /* *-------------------------------------------------------------------------- * * mongoc_client_connect_unix -- * * Connect to a MongoDB server using a UNIX domain socket. * * Returns: * A newly allocated mongoc_stream_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error is set if return value is NULL. * *-------------------------------------------------------------------------- */ static mongoc_stream_t * mongoc_client_connect_unix (const mongoc_uri_t *uri, const mongoc_host_list_t *host, bson_error_t *error) { #ifdef _WIN32 ENTRY; bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "UNIX domain sockets not supported on win32."); RETURN (NULL); #else struct sockaddr_un saddr; mongoc_socket_t *sock; mongoc_stream_t *ret = NULL; ENTRY; BSON_ASSERT (uri); BSON_ASSERT (host); memset (&saddr, 0, sizeof saddr); saddr.sun_family = AF_UNIX; bson_snprintf (saddr.sun_path, sizeof saddr.sun_path - 1, "%s", host->host); sock = mongoc_socket_new (AF_UNIX, SOCK_STREAM, 0); if (sock == NULL) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to create socket."); RETURN (NULL); } if (-1 == mongoc_socket_connect (sock, (struct sockaddr *)&saddr, sizeof saddr, -1)) { mongoc_socket_destroy (sock); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "Failed to connect to UNIX domain socket."); RETURN (NULL); } ret = mongoc_stream_socket_new (sock); RETURN (ret); #endif } /* *-------------------------------------------------------------------------- * * mongoc_client_default_stream_initiator -- * * A mongoc_stream_initiator_t that will handle the various type * of supported sockets by MongoDB including TCP and UNIX. * * Language binding authors may want to implement an alternate * version of this method to use their native stream format. * * Returns: * A mongoc_stream_t if successful; otherwise NULL and @error is set. * * Side effects: * @error is set if return value is NULL. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_client_default_stream_initiator (const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *user_data, bson_error_t *error) { mongoc_stream_t *base_stream = NULL; #ifdef MONGOC_ENABLE_SSL mongoc_client_t *client = (mongoc_client_t *)user_data; const char *mechanism; int32_t connecttimeoutms; #endif BSON_ASSERT (uri); BSON_ASSERT (host); #ifndef MONGOC_ENABLE_SSL if (mongoc_uri_get_ssl (uri)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_NO_ACCEPTABLE_PEER, "SSL is not enabled in this build of mongo-c-driver."); return NULL; } #endif switch (host->family) { #if defined(AF_INET6) case AF_INET6: #endif case AF_INET: base_stream = mongoc_client_connect_tcp (uri, host, error); break; case AF_UNIX: base_stream = mongoc_client_connect_unix (uri, host, error); break; default: bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_INVALID_TYPE, "Invalid address family: 0x%02x", host->family); break; } #ifdef MONGOC_ENABLE_SSL if (base_stream) { mechanism = mongoc_uri_get_auth_mechanism (uri); if (client->use_ssl || (mechanism && (0 == strcmp (mechanism, "MONGODB-X509")))) { base_stream = mongoc_stream_tls_new (base_stream, &client->ssl_opts, true); if (!base_stream) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed initialize TLS state."); return NULL; } connecttimeoutms = mongoc_uri_get_option_as_int32 ( uri, "connecttimeoutms", MONGOC_DEFAULT_CONNECTTIMEOUTMS); if (!mongoc_stream_tls_do_handshake (base_stream, connecttimeoutms) || !mongoc_stream_tls_check_cert (base_stream, host->host)) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to handshake and validate TLS certificate."); mongoc_stream_destroy (base_stream); return NULL; } } } #endif return base_stream ? mongoc_stream_buffered_new (base_stream, 1024) : NULL; } /* *-------------------------------------------------------------------------- * * _mongoc_client_create_stream -- * * INTERNAL API * * This function is used by the mongoc_cluster_t to initiate a * new stream. This is done because cluster is private API and * those using mongoc_client_t may need to override this process. * * This function calls the default initiator for new streams. * * Returns: * A newly allocated mongoc_stream_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error is set if return value is NULL. * *-------------------------------------------------------------------------- */ mongoc_stream_t * _mongoc_client_create_stream (mongoc_client_t *client, const mongoc_host_list_t *host, bson_error_t *error) { BSON_ASSERT (client); BSON_ASSERT (host); return client->initiator (client->uri, host, client->initiator_data, error); } /* *-------------------------------------------------------------------------- * * _mongoc_client_recv -- * * Receives a RPC from a remote MongoDB cluster node. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @error is set if return value is false. * *-------------------------------------------------------------------------- */ bool _mongoc_client_recv (mongoc_client_t *client, mongoc_rpc_t *rpc, mongoc_buffer_t *buffer, mongoc_server_stream_t *server_stream, bson_error_t *error) { BSON_ASSERT (client); BSON_ASSERT (rpc); BSON_ASSERT (buffer); BSON_ASSERT (server_stream); if (!mongoc_cluster_try_recv (&client->cluster, rpc, buffer, server_stream, error)) { mongoc_topology_invalidate_server (client->topology, server_stream->sd->id); return false; } return true; } /* *-------------------------------------------------------------------------- * * _bson_to_error -- * * A helper routine to convert a bson document to a bson_error_t. * * Returns: * None. * * Side effects: * @error is set if non-null. * *-------------------------------------------------------------------------- */ static void _bson_to_error (const bson_t *b, bson_error_t *error) { bson_iter_t iter; int code = 0; BSON_ASSERT (b); if (!error) { return; } if (bson_iter_init_find(&iter, b, "code") && BSON_ITER_HOLDS_INT32(&iter)) { code = bson_iter_int32(&iter); } if (bson_iter_init_find(&iter, b, "$err") && BSON_ITER_HOLDS_UTF8(&iter)) { bson_set_error(error, MONGOC_ERROR_QUERY, code, "%s", bson_iter_utf8(&iter, NULL)); return; } if (bson_iter_init_find(&iter, b, "errmsg") && BSON_ITER_HOLDS_UTF8(&iter)) { bson_set_error(error, MONGOC_ERROR_QUERY, code, "%s", bson_iter_utf8(&iter, NULL)); return; } bson_set_error(error, MONGOC_ERROR_QUERY, MONGOC_ERROR_QUERY_FAILURE, "An unknown error ocurred on the server."); } /* *-------------------------------------------------------------------------- * * mongoc_client_recv_gle -- * * INTERNAL API * * This function is used to receive the next RPC from a cluster * node, expecting it to be the response to a getlasterror command. * * The RPC is parsed into @error if it is an error and false is * returned. * * If the operation was successful, true is returned. * * if @gle_doc is not NULL, then the actual response document for * the gle command will be stored as an out parameter. The caller * is responsible for freeing it in this case. * * Returns: * true if getlasterror was success; otherwise false. * * Side effects: * @gle_doc will be set if non NULL and a reply was received. * @error if return value is false, and @gle_doc is set to NULL. * *-------------------------------------------------------------------------- */ bool _mongoc_client_recv_gle (mongoc_client_t *client, mongoc_server_stream_t *server_stream, bson_t **gle_doc, bson_error_t *error) { mongoc_buffer_t buffer; mongoc_rpc_t rpc; bson_iter_t iter; bool ret = false; bson_t b; ENTRY; BSON_ASSERT (client); BSON_ASSERT (server_stream); if (gle_doc) { *gle_doc = NULL; } _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); if (!mongoc_cluster_try_recv (&client->cluster, &rpc, &buffer, server_stream, error)) { mongoc_topology_invalidate_server (client->topology, server_stream->sd->id); GOTO (cleanup); } if (rpc.header.opcode != MONGOC_OPCODE_REPLY) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Received message other than OP_REPLY."); GOTO (cleanup); } if (_mongoc_rpc_reply_get_first (&rpc.reply, &b)) { if ((rpc.reply.flags & MONGOC_REPLY_QUERY_FAILURE)) { _bson_to_error (&b, error); bson_destroy (&b); GOTO (cleanup); } if (gle_doc) { *gle_doc = bson_copy (&b); } if (!bson_iter_init_find (&iter, &b, "ok") || BSON_ITER_HOLDS_DOUBLE (&iter)) { if (bson_iter_double (&iter) == 0.0) { _bson_to_error (&b, error); } } bson_destroy (&b); ret = true; } cleanup: _mongoc_buffer_destroy (&buffer); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_client_new -- * * Create a new mongoc_client_t using the URI provided. * * @uri should be a MongoDB URI string such as "mongodb://localhost/" * More information on the format can be found at * http://docs.mongodb.org/manual/reference/connection-string/ * * Returns: * A newly allocated mongoc_client_t or NULL if @uri_string is * invalid. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_client_t * mongoc_client_new(const char *uri_string) { mongoc_topology_t *topology; mongoc_client_t *client; mongoc_uri_t *uri; if (!uri_string) { uri_string = "mongodb://127.0.0.1/"; } if (!(uri = mongoc_uri_new (uri_string))) { return NULL; } topology = mongoc_topology_new(uri, true); client = _mongoc_client_new_from_uri (uri, topology); mongoc_uri_destroy (uri); return client; } /* *-------------------------------------------------------------------------- * * mongoc_client_set_ssl_opts * * set ssl opts for a client * * Returns: * Nothing * * Side effects: * None. * *-------------------------------------------------------------------------- */ #ifdef MONGOC_ENABLE_SSL void mongoc_client_set_ssl_opts (mongoc_client_t *client, const mongoc_ssl_opt_t *opts) { BSON_ASSERT (client); BSON_ASSERT (opts); client->use_ssl = true; memcpy (&client->ssl_opts, opts, sizeof client->ssl_opts); bson_free (client->pem_subject); client->pem_subject = NULL; if (opts->pem_file) { client->pem_subject = _mongoc_ssl_extract_subject (opts->pem_file); } if (client->topology->single_threaded) { mongoc_topology_scanner_set_ssl_opts (client->topology->scanner, &client->ssl_opts); } } #endif /* *-------------------------------------------------------------------------- * * mongoc_client_new_from_uri -- * * Create a new mongoc_client_t for a mongoc_uri_t. * * Returns: * A newly allocated mongoc_client_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_client_t * mongoc_client_new_from_uri (const mongoc_uri_t *uri) { mongoc_topology_t *topology; topology = mongoc_topology_new (uri, true); return _mongoc_client_new_from_uri (uri, topology); } /* *-------------------------------------------------------------------------- * * _mongoc_client_new_from_uri -- * * Create a new mongoc_client_t for a mongoc_uri_t and a given * topology object. * * Returns: * A newly allocated mongoc_client_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_client_t * _mongoc_client_new_from_uri (const mongoc_uri_t *uri, mongoc_topology_t *topology) { mongoc_client_t *client; const mongoc_read_prefs_t *read_prefs; const mongoc_read_concern_t *read_concern; const mongoc_write_concern_t *write_concern; BSON_ASSERT (uri); #ifndef MONGOC_ENABLE_SSL if (mongoc_uri_get_ssl (uri)) { MONGOC_ERROR ("Can't create SSL client, SSL not enabled in this build."); return NULL; } #endif client = (mongoc_client_t *)bson_malloc0(sizeof *client); client->uri = mongoc_uri_copy (uri); client->request_id = rand (); client->initiator = mongoc_client_default_stream_initiator; client->initiator_data = client; client->topology = topology; write_concern = mongoc_uri_get_write_concern (client->uri); client->write_concern = mongoc_write_concern_copy (write_concern); read_concern = mongoc_uri_get_read_concern (client->uri); client->read_concern = mongoc_read_concern_copy (read_concern); read_prefs = mongoc_uri_get_read_prefs_t (client->uri); client->read_prefs = mongoc_read_prefs_copy (read_prefs); mongoc_cluster_init (&client->cluster, client->uri, client); #ifdef MONGOC_ENABLE_SSL client->use_ssl = false; if (mongoc_uri_get_ssl (client->uri)) { /* sets use_ssl = true */ mongoc_client_set_ssl_opts (client, mongoc_ssl_opt_get_default ()); } #endif mongoc_counter_clients_active_inc (); return client; } /* *-------------------------------------------------------------------------- * * mongoc_client_destroy -- * * Destroys a mongoc_client_t and cleans up all resources associated * with the client instance. * * Returns: * None. * * Side effects: * @client is destroyed. * *-------------------------------------------------------------------------- */ void mongoc_client_destroy (mongoc_client_t *client) { if (client) { #ifdef MONGOC_ENABLE_SSL bson_free (client->pem_subject); #endif if (client->topology->single_threaded) { mongoc_topology_destroy(client->topology); } mongoc_write_concern_destroy (client->write_concern); mongoc_read_concern_destroy (client->read_concern); mongoc_read_prefs_destroy (client->read_prefs); mongoc_cluster_destroy (&client->cluster); mongoc_uri_destroy (client->uri); bson_free (client); mongoc_counter_clients_active_dec (); mongoc_counter_clients_disposed_inc (); } } /* *-------------------------------------------------------------------------- * * mongoc_client_get_uri -- * * Fetch the URI used for @client. * * Returns: * A mongoc_uri_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_uri_t * mongoc_client_get_uri (const mongoc_client_t *client) { BSON_ASSERT (client); return client->uri; } /* *-------------------------------------------------------------------------- * * mongoc_client_get_database -- * * Fetches a newly allocated database structure to communicate with * a database over @client. * * @database should be a db name such as "test". * * This structure should be freed when the caller is done with it * using mongoc_database_destroy(). * * Returns: * A newly allocated mongoc_database_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_database_t * mongoc_client_get_database (mongoc_client_t *client, const char *name) { BSON_ASSERT (client); BSON_ASSERT (name); return _mongoc_database_new(client, name, client->read_prefs, client->read_concern, client->write_concern); } /* *-------------------------------------------------------------------------- * * mongoc_client_get_default_database -- * * Get the database named in the MongoDB connection URI, or NULL * if none was specified in the URI. * * This structure should be freed when the caller is done with it * using mongoc_database_destroy(). * * Returns: * A newly allocated mongoc_database_t or NULL. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_database_t * mongoc_client_get_default_database (mongoc_client_t *client) { const char *db; BSON_ASSERT (client); db = mongoc_uri_get_database (client->uri); if (db) { return mongoc_client_get_database (client, db); } return NULL; } /* *-------------------------------------------------------------------------- * * mongoc_client_get_collection -- * * This function returns a newly allocated collection structure. * * @db should be the name of the database, such as "test". * @collection should be the name of the collection such as "test". * * The above would result in the namespace "test.test". * * You should free this structure when you are done with it using * mongoc_collection_destroy(). * * Returns: * A newly allocated mongoc_collection_t that should be freed with * mongoc_collection_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_collection_t * mongoc_client_get_collection (mongoc_client_t *client, const char *db, const char *collection) { BSON_ASSERT (client); BSON_ASSERT (db); BSON_ASSERT (collection); return _mongoc_collection_new(client, db, collection, client->read_prefs, client->read_concern, client->write_concern); } /* *-------------------------------------------------------------------------- * * mongoc_client_get_gridfs -- * * This function returns a newly allocated collection structure. * * @db should be the name of the database, such as "test". * * @prefix optional prefix for GridFS collection names, or NULL. Default * is "fs", thus the default collection names for GridFS are "fs.files" * and "fs.chunks". * * Returns: * A newly allocated mongoc_gridfs_t that should be freed with * mongoc_gridfs_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_gridfs_t * mongoc_client_get_gridfs (mongoc_client_t *client, const char *db, const char *prefix, bson_error_t *error) { BSON_ASSERT (client); BSON_ASSERT (db); if (! prefix) { prefix = "fs"; } return _mongoc_gridfs_new(client, db, prefix, error); } /* *-------------------------------------------------------------------------- * * mongoc_client_get_write_concern -- * * Fetches the default write concern for @client. * * Returns: * A mongoc_write_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_write_concern_t * mongoc_client_get_write_concern (const mongoc_client_t *client) { BSON_ASSERT (client); return client->write_concern; } /* *-------------------------------------------------------------------------- * * mongoc_client_set_write_concern -- * * Sets the default write concern for @client. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_client_set_write_concern (mongoc_client_t *client, const mongoc_write_concern_t *write_concern) { BSON_ASSERT (client); if (write_concern != client->write_concern) { if (client->write_concern) { mongoc_write_concern_destroy(client->write_concern); } client->write_concern = write_concern ? mongoc_write_concern_copy(write_concern) : mongoc_write_concern_new(); } } /* *-------------------------------------------------------------------------- * * mongoc_client_get_read_concern -- * * Fetches the default read concern for @client. * * Returns: * A mongoc_read_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_concern_t * mongoc_client_get_read_concern (const mongoc_client_t *client) { BSON_ASSERT (client); return client->read_concern; } /* *-------------------------------------------------------------------------- * * mongoc_client_set_read_concern -- * * Sets the default read concern for @client. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_client_set_read_concern (mongoc_client_t *client, const mongoc_read_concern_t *read_concern) { BSON_ASSERT (client); if (read_concern != client->read_concern) { if (client->read_concern) { mongoc_read_concern_destroy (client->read_concern); } client->read_concern = read_concern ? mongoc_read_concern_copy (read_concern) : mongoc_read_concern_new (); } } /* *-------------------------------------------------------------------------- * * mongoc_client_get_read_prefs -- * * Fetch the default read preferences for @client. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_prefs_t * mongoc_client_get_read_prefs (const mongoc_client_t *client) { BSON_ASSERT (client); return client->read_prefs; } /* *-------------------------------------------------------------------------- * * mongoc_client_set_read_prefs -- * * Set the default read preferences for @client. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_client_set_read_prefs (mongoc_client_t *client, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (client); if (read_prefs != client->read_prefs) { if (client->read_prefs) { mongoc_read_prefs_destroy(client->read_prefs); } client->read_prefs = read_prefs ? mongoc_read_prefs_copy(read_prefs) : mongoc_read_prefs_new(MONGOC_READ_PRIMARY); } } mongoc_cursor_t * mongoc_client_command (mongoc_client_t *client, const char *db_name, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) { char ns[MONGOC_NAMESPACE_MAX]; BSON_ASSERT (client); BSON_ASSERT (db_name); BSON_ASSERT (query); if (!read_prefs) { read_prefs = client->read_prefs; } /* * Allow a caller to provide a fully qualified namespace */ if (NULL == strstr (db_name, "$cmd")) { bson_snprintf (ns, sizeof ns, "%s.$cmd", db_name); db_name = ns; } return _mongoc_cursor_new (client, db_name, flags, skip, limit, batch_size, true, query, fields, read_prefs, NULL); } /** * mongoc_client_command_simple: * @client: A mongoc_client_t. * @db_name: The namespace, such as "admin". * @command: The command to execute. * @read_prefs: The read preferences or NULL. * @reply: A location for the reply document or NULL. * @error: A location for the error, or NULL. * * This wrapper around mongoc_client_command() aims to make it simpler to * run a command and check the output result. * * false is returned if the command failed to be delivered or if the execution * of the command failed. For example, a command that returns {'ok': 0} will * result in this function returning false. * * To allow the caller to disambiguate between command execution failure and * failure to send the command, reply will always be set if non-NULL. The * caller should release this with bson_destroy(). * * Returns: true if the command executed and resulted in success. Otherwise * false and @error is set. @reply is always set, either to the resulting * document or an empty bson document upon failure. */ bool mongoc_client_command_simple (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error) { mongoc_cluster_t *cluster; mongoc_server_stream_t *server_stream; mongoc_apply_read_prefs_result_t result = READ_PREFS_RESULT_INIT; bool ret = false; ENTRY; BSON_ASSERT (client); BSON_ASSERT (db_name); BSON_ASSERT (command); cluster = &client->cluster; server_stream = mongoc_cluster_stream_for_reads (cluster, read_prefs, error); if (!server_stream) { if (reply) { bson_init (reply); } GOTO (done); } apply_read_preferences (read_prefs, server_stream, command, MONGOC_QUERY_NONE, &result); ret = mongoc_cluster_run_command (cluster, server_stream->stream, result.flags, db_name, result.query_with_read_prefs, reply, error); done: mongoc_server_stream_cleanup (server_stream); apply_read_prefs_result_cleanup (&result); RETURN (ret); } void _mongoc_client_kill_cursor (mongoc_client_t *client, uint32_t server_id, int64_t cursor_id, const char *db, const char *collection) { mongoc_server_stream_t *server_stream; ENTRY; BSON_ASSERT (client); BSON_ASSERT (cursor_id); /* don't attempt reconnect if server unavailable, and ignore errors */ server_stream = mongoc_cluster_stream_for_server (&client->cluster, server_id, false /* reconnect_ok */, NULL /* error */); if (!server_stream) { return; } if (db && collection && server_stream->sd->max_wire_version >= WIRE_VERSION_KILLCURSORS_CMD) { _mongoc_client_killcursors_command (&client->cluster, server_stream, cursor_id, db, collection); } else { _mongoc_client_op_killcursors (&client->cluster, server_stream, cursor_id); } mongoc_server_stream_cleanup (server_stream); EXIT; } static void _mongoc_client_op_killcursors (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, int64_t cursor_id) { mongoc_rpc_t rpc = { { 0 } }; rpc.kill_cursors.msg_len = 0; rpc.kill_cursors.request_id = 0; rpc.kill_cursors.response_to = 0; rpc.kill_cursors.opcode = MONGOC_OPCODE_KILL_CURSORS; rpc.kill_cursors.zero = 0; rpc.kill_cursors.cursors = &cursor_id; rpc.kill_cursors.n_cursors = 1; mongoc_cluster_sendv_to_server (cluster, &rpc, 1, server_stream, NULL, NULL); } static void _mongoc_client_killcursors_command (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, int64_t cursor_id, const char *db, const char *collection) { bson_t command = BSON_INITIALIZER; bson_t child; bson_append_utf8 (&command, "killCursors", 11, collection, -1); bson_append_array_begin (&command, "cursors", 7, &child); bson_append_int64 (&child, "0", 1, cursor_id); bson_append_array_end (&command, &child); /* Find, getMore And killCursors Commands Spec: "The result from the * killCursors command MAY be safely ignored." */ mongoc_cluster_run_command (cluster, server_stream->stream, MONGOC_QUERY_SLAVE_OK, db, &command, NULL, NULL); bson_destroy (&command); } /* *-------------------------------------------------------------------------- * * mongoc_client_kill_cursor -- * * Destroy a cursor on the server. * * NOTE: this is only reliable when connected to a single mongod or * mongos. If connected to a replica set, the driver attempts to * kill the cursor on the primary. If connected to multiple mongoses * the kill-cursors message is sent to a *random* mongos. * * If no primary, mongos, or standalone server is known, return * without attempting to reconnect. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_client_kill_cursor (mongoc_client_t *client, int64_t cursor_id) { mongoc_topology_t *topology; mongoc_server_description_t *selected_server; mongoc_read_prefs_t *read_prefs; uint32_t server_id = 0; topology = client->topology; read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); mongoc_mutex_lock (&topology->mutex); /* see if there's a known writable server - do no I/O or retries */ selected_server = mongoc_topology_description_select(&topology->description, MONGOC_SS_WRITE, read_prefs, 15); if (selected_server) { server_id = selected_server->id; } mongoc_mutex_unlock (&topology->mutex); if (server_id) { _mongoc_client_kill_cursor (client, selected_server->id, cursor_id, NULL /* db */, NULL /* collection */); } else { MONGOC_INFO ("No server available for mongoc_client_kill_cursor"); } mongoc_read_prefs_destroy (read_prefs); } char ** mongoc_client_get_database_names (mongoc_client_t *client, bson_error_t *error) { bson_iter_t iter; const char *name; char **ret = NULL; int i = 0; mongoc_cursor_t *cursor; const bson_t *doc; BSON_ASSERT (client); cursor = mongoc_client_find_databases (client, error); while (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init (&iter, doc) && bson_iter_find (&iter, "name") && BSON_ITER_HOLDS_UTF8 (&iter) && (name = bson_iter_utf8 (&iter, NULL)) && (0 != strcmp (name, "local"))) { ret = (char **)bson_realloc (ret, sizeof(char*) * (i + 2)); ret [i] = bson_strdup (name); ret [++i] = NULL; } } if (!ret && !mongoc_cursor_error (cursor, error)) { ret = (char **)bson_malloc0 (sizeof (void*)); } mongoc_cursor_destroy (cursor); return ret; } mongoc_cursor_t * mongoc_client_find_databases (mongoc_client_t *client, bson_error_t *error) { bson_t cmd = BSON_INITIALIZER; mongoc_cursor_t *cursor; BSON_ASSERT (client); BSON_APPEND_INT32 (&cmd, "listDatabases", 1); cursor = _mongoc_cursor_new (client, "admin", MONGOC_QUERY_SLAVE_OK, 0, 0, 0, true, NULL, NULL, NULL, NULL); _mongoc_cursor_array_init (cursor, &cmd, "databases"); bson_destroy (&cmd); return cursor; } int32_t mongoc_client_get_max_message_size (mongoc_client_t *client) /* IN */ { BSON_ASSERT (client); return mongoc_cluster_get_max_msg_size (&client->cluster); } int32_t mongoc_client_get_max_bson_size (mongoc_client_t *client) /* IN */ { BSON_ASSERT (client); return mongoc_cluster_get_max_bson_obj_size (&client->cluster); } bool mongoc_client_get_server_status (mongoc_client_t *client, /* IN */ mongoc_read_prefs_t *read_prefs, /* IN */ bson_t *reply, /* OUT */ bson_error_t *error) /* OUT */ { bson_t cmd = BSON_INITIALIZER; bool ret = false; BSON_ASSERT (client); BSON_APPEND_INT32 (&cmd, "serverStatus", 1); ret = mongoc_client_command_simple (client, "admin", &cmd, read_prefs, reply, error); bson_destroy (&cmd); return ret; } void mongoc_client_set_stream_initiator (mongoc_client_t *client, mongoc_stream_initiator_t initiator, void *user_data) { BSON_ASSERT (client); if (!initiator) { initiator = mongoc_client_default_stream_initiator; user_data = client; } else { MONGOC_DEBUG ("Using custom stream initiator."); } client->initiator = initiator; client->initiator_data = user_data; if (client->topology->single_threaded) { mongoc_topology_scanner_set_stream_initiator (client->topology->scanner, initiator, user_data); } } libmongoc-1.3.1/src/mongoc/mongoc-client.h000066400000000000000000000211641264720626300204610ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CLIENT_H #define MONGOC_CLIENT_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-collection.h" #include "mongoc-config.h" #include "mongoc-cursor.h" #include "mongoc-database.h" #include "mongoc-gridfs.h" #include "mongoc-index.h" #include "mongoc-read-prefs.h" #ifdef MONGOC_ENABLE_SSL # include "mongoc-ssl.h" #endif #include "mongoc-stream.h" #include "mongoc-uri.h" #include "mongoc-write-concern.h" #include "mongoc-read-concern.h" BSON_BEGIN_DECLS #define MONGOC_NAMESPACE_MAX 128 #ifndef MONGOC_DEFAULT_CONNECTTIMEOUTMS #define MONGOC_DEFAULT_CONNECTTIMEOUTMS (10 * 1000L) #endif #ifndef MONGOC_DEFAULT_SOCKETTIMEOUTMS /* * NOTE: The default socket timeout for connections is 5 minutes. This * means that if your MongoDB server dies or becomes unavailable * it will take 5 minutes to detect this. * * You can change this by providing sockettimeoutms= in your * connection URI. */ #define MONGOC_DEFAULT_SOCKETTIMEOUTMS (1000L * 60L * 5L) #endif /** * mongoc_client_t: * * The mongoc_client_t structure maintains information about a connection to * a MongoDB server. */ typedef struct _mongoc_client_t mongoc_client_t; /** * mongoc_stream_initiator_t: * @uri: The uri and options for the stream. * @host: The host and port (or UNIX domain socket path) to connect to. * @user_data: The pointer passed to mongoc_client_set_stream_initiator. * @error: A location for an error. * * Creates a new mongoc_stream_t for the host and port. Begin a * non-blocking connect and return immediately. * * This can be used by language bindings to create network transports other * than those built into libmongoc. An example of such would be the streams * API provided by PHP. * * Returns: A newly allocated mongoc_stream_t or NULL on failure. */ typedef mongoc_stream_t *(*mongoc_stream_initiator_t) (const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *user_data, bson_error_t *error); mongoc_client_t *mongoc_client_new (const char *uri_string); mongoc_client_t *mongoc_client_new_from_uri (const mongoc_uri_t *uri); const mongoc_uri_t *mongoc_client_get_uri (const mongoc_client_t *client); void mongoc_client_set_stream_initiator (mongoc_client_t *client, mongoc_stream_initiator_t initiator, void *user_data); mongoc_cursor_t *mongoc_client_command (mongoc_client_t *client, const char *db_name, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs); void mongoc_client_kill_cursor (mongoc_client_t *client, int64_t cursor_id) BSON_GNUC_DEPRECATED; bool mongoc_client_command_simple (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error); void mongoc_client_destroy (mongoc_client_t *client); mongoc_database_t *mongoc_client_get_database (mongoc_client_t *client, const char *name); mongoc_database_t *mongoc_client_get_default_database (mongoc_client_t *client); mongoc_gridfs_t *mongoc_client_get_gridfs (mongoc_client_t *client, const char *db, const char *prefix, bson_error_t *error); mongoc_collection_t *mongoc_client_get_collection (mongoc_client_t *client, const char *db, const char *collection); char **mongoc_client_get_database_names (mongoc_client_t *client, bson_error_t *error); mongoc_cursor_t *mongoc_client_find_databases (mongoc_client_t *client, bson_error_t *error); bool mongoc_client_get_server_status (mongoc_client_t *client, mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error); int32_t mongoc_client_get_max_message_size (mongoc_client_t *client) BSON_GNUC_DEPRECATED; int32_t mongoc_client_get_max_bson_size (mongoc_client_t *client) BSON_GNUC_DEPRECATED; const mongoc_write_concern_t *mongoc_client_get_write_concern (const mongoc_client_t *client); void mongoc_client_set_write_concern (mongoc_client_t *client, const mongoc_write_concern_t *write_concern); const mongoc_read_concern_t *mongoc_client_get_read_concern (const mongoc_client_t *client); void mongoc_client_set_read_concern (mongoc_client_t *client, const mongoc_read_concern_t *read_concern); const mongoc_read_prefs_t *mongoc_client_get_read_prefs (const mongoc_client_t *client); void mongoc_client_set_read_prefs (mongoc_client_t *client, const mongoc_read_prefs_t *read_prefs); #ifdef MONGOC_ENABLE_SSL void mongoc_client_set_ssl_opts (mongoc_client_t *client, const mongoc_ssl_opt_t *opts); #endif BSON_END_DECLS #endif /* MONGOC_CLIENT_H */ libmongoc-1.3.1/src/mongoc/mongoc-cluster-private.h000066400000000000000000000114441264720626300223340ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CLUSTER_PRIVATE_H #define MONGOC_CLUSTER_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-array-private.h" #include "mongoc-buffer-private.h" #include "mongoc-config.h" #include "mongoc-client.h" #include "mongoc-list-private.h" #include "mongoc-opcode.h" #include "mongoc-read-prefs.h" #include "mongoc-rpc-private.h" #include "mongoc-server-stream-private.h" #include "mongoc-set-private.h" #include "mongoc-stream.h" #include "mongoc-topology-description-private.h" #include "mongoc-uri.h" #include "mongoc-write-concern.h" BSON_BEGIN_DECLS typedef struct _mongoc_cluster_node_t { mongoc_stream_t *stream; int32_t max_wire_version; int32_t min_wire_version; int32_t max_write_batch_size; int32_t max_bson_obj_size; int32_t max_msg_size; int64_t timestamp; } mongoc_cluster_node_t; typedef struct _mongoc_cluster_t { uint32_t request_id; uint32_t sockettimeoutms; uint32_t socketcheckintervalms; mongoc_uri_t *uri; unsigned requires_auth : 1; mongoc_client_t *client; mongoc_set_t *nodes; mongoc_array_t iov; } mongoc_cluster_t; void mongoc_cluster_init (mongoc_cluster_t *cluster, const mongoc_uri_t *uri, void *client); void mongoc_cluster_destroy (mongoc_cluster_t *cluster); void mongoc_cluster_disconnect_node (mongoc_cluster_t *cluster, uint32_t id); int32_t mongoc_cluster_get_max_bson_obj_size (mongoc_cluster_t *cluster); int32_t mongoc_cluster_get_max_msg_size (mongoc_cluster_t *cluster); int32_t mongoc_cluster_node_max_wire_version (mongoc_cluster_t *cluster, uint32_t server_id); int32_t mongoc_cluster_node_min_wire_version (mongoc_cluster_t *cluster, uint32_t server_id); bool mongoc_cluster_sendv_to_server (mongoc_cluster_t *cluster, mongoc_rpc_t *rpcs, size_t rpcs_len, mongoc_server_stream_t *server_stream, const mongoc_write_concern_t *write_concern, bson_error_t *error); bool mongoc_cluster_try_recv (mongoc_cluster_t *cluster, mongoc_rpc_t *rpc, mongoc_buffer_t *buffer, mongoc_server_stream_t *server_stream, bson_error_t *error); mongoc_server_stream_t * mongoc_cluster_stream_for_reads (mongoc_cluster_t *cluster, const mongoc_read_prefs_t *read_prefs, bson_error_t *error); mongoc_server_stream_t * mongoc_cluster_stream_for_writes (mongoc_cluster_t *cluster, bson_error_t *error); mongoc_server_stream_t * mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster, uint32_t server_id, bool reconnect_ok, bson_error_t *error); bool mongoc_cluster_run_command_rpc (mongoc_cluster_t *cluster, mongoc_stream_t *stream, const char *command_name, mongoc_rpc_t *rpc, mongoc_rpc_t *reply_rpc, mongoc_buffer_t *buffer, bson_error_t *error); bool mongoc_cluster_run_command (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_query_flags_t flags, const char *db_name, const bson_t *command, bson_t *reply, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_CLUSTER_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-cluster.c000066400000000000000000002065351264720626300206660ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-config.h" #ifdef MONGOC_ENABLE_SASL #include #include #endif #include #include "mongoc-cluster-private.h" #include "mongoc-client-private.h" #include "mongoc-counters-private.h" #include "mongoc-config.h" #include "mongoc-error.h" #include "mongoc-host-list-private.h" #include "mongoc-log.h" #ifdef MONGOC_ENABLE_SASL #include "mongoc-sasl-private.h" #endif #include "mongoc-b64-private.h" #include "mongoc-scram-private.h" #include "mongoc-set-private.h" #include "mongoc-socket.h" #include "mongoc-stream-private.h" #include "mongoc-stream-socket.h" #include "mongoc-thread-private.h" #include "mongoc-topology-private.h" #include "mongoc-trace.h" #include "mongoc-util-private.h" #include "mongoc-write-concern-private.h" #include "mongoc-uri-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "cluster" #define CHECK_CLOSED_DURATION_MSEC 1000 #define DB_AND_CMD_FROM_COLLECTION(outstr, name) \ do { \ const char *dot = strchr(name, '.'); \ if (!dot || ((dot - name) > (sizeof outstr - 6))) { \ bson_snprintf(outstr, sizeof outstr, "admin.$cmd"); \ } else { \ memcpy(outstr, name, dot - name); \ memcpy(outstr + (dot - name), ".$cmd", 6); \ } \ } while (0) static mongoc_server_stream_t * mongoc_cluster_fetch_stream_single (mongoc_cluster_t *cluster, mongoc_server_description_t *sd, bool reconnect_ok, bson_error_t *error); static mongoc_server_stream_t * mongoc_cluster_fetch_stream_pooled (mongoc_cluster_t *cluster, mongoc_server_description_t *sd, bool reconnect_ok, bson_error_t *error); static void _bson_error_message_printf (bson_error_t *error, const char *format, ...) BSON_GNUC_PRINTF (2, 3); /* Allows caller to safely overwrite error->message with a formatted string, * even if the formatted string includes original error->message. */ static void _bson_error_message_printf (bson_error_t *error, const char *format, ...) { va_list args; char error_message[sizeof error->message]; if (error) { va_start (args, format); bson_vsnprintf (error_message, sizeof error->message, format, args); va_end (args); bson_strncpy (error->message, error_message, sizeof error->message); } } /* *-------------------------------------------------------------------------- * * mongoc_cluster_run_command_rpc -- * * Internal function to run a command on a given stream and * read the response into @reply_rpc. @rpc and @reply_rpc can be * the same to reuse storage. @buffer should be initialized before * passing it in. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * On success, @buffer and @reply_rpc are filled out with the reply. * *-------------------------------------------------------------------------- */ bool mongoc_cluster_run_command_rpc (mongoc_cluster_t *cluster, mongoc_stream_t *stream, const char *command_name, mongoc_rpc_t *rpc, mongoc_rpc_t *reply_rpc, mongoc_buffer_t *buffer, bson_error_t *error) { mongoc_array_t ar; int32_t msg_len; bool error_set = false; bool ret = false; char db[MONGOC_NAMESPACE_MAX]; ENTRY; BSON_ASSERT(cluster); BSON_ASSERT(stream); _mongoc_array_init (&ar, sizeof (mongoc_iovec_t)); if (cluster->client->in_exhaust) { bson_set_error(error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_IN_EXHAUST, "A cursor derived from this client is in exhaust."); error_set = true; GOTO (done); } rpc->query.request_id = ++cluster->request_id; _mongoc_rpc_gather (rpc, &ar); _mongoc_rpc_swab_to_le (rpc); if (!_mongoc_stream_writev_full (stream, (mongoc_iovec_t *)ar.data, ar.len, cluster->sockettimeoutms, error) || !_mongoc_buffer_append_from_stream (buffer, stream, 4, cluster->sockettimeoutms, error)) { /* add info about the command to writev_full's error message */ _mongoc_get_db_name (rpc->query.collection, db); _bson_error_message_printf ( error, "Failed to send \"%s\" command with database \"%s\": %s", command_name, db, error->message); error_set = true; GOTO (done); } BSON_ASSERT (buffer->len == 4); memcpy (&msg_len, buffer->data, 4); msg_len = BSON_UINT32_FROM_LE(msg_len); if ((msg_len < 16) || (msg_len > MONGOC_DEFAULT_MAX_MSG_SIZE)) { GOTO (done); } if (!_mongoc_buffer_append_from_stream (buffer, stream, (size_t) msg_len - 4, cluster->sockettimeoutms, error)) { error_set = true; GOTO (done); } if (!_mongoc_rpc_scatter (reply_rpc, buffer->data, buffer->len)) { GOTO (done); } _mongoc_rpc_swab_from_le (reply_rpc); if (reply_rpc->header.opcode != MONGOC_OPCODE_REPLY) { GOTO (done); } ret = true; done: _mongoc_array_destroy (&ar); if (!ret && !error_set) { /* generic error */ bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply from server."); } RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_cluster_run_command -- * * Internal function to run a command on a given stream. * @error and @reply are optional out-pointers. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @reply is set and should ALWAYS be released with bson_destroy(). * *-------------------------------------------------------------------------- */ bool mongoc_cluster_run_command (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_query_flags_t flags, const char *db_name, const bson_t *command, bson_t *reply, bson_error_t *error) { char ns[MONGOC_NAMESPACE_MAX]; mongoc_rpc_t rpc; bson_t reply_local; bool ret = false; bool reply_local_initialized = false; mongoc_buffer_t buffer; _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); bson_snprintf (ns, sizeof ns, "%s.$cmd", db_name); _mongoc_rpc_prep_command (&rpc, ns, command, flags); /* we can reuse the query rpc for the reply */ if (!mongoc_cluster_run_command_rpc (cluster, stream, _mongoc_get_command_name (command), &rpc, &rpc, &buffer, error)) { GOTO (done); } /* static-init reply_local to point into buffer */ if (!_mongoc_rpc_reply_get_first(&rpc.reply, &reply_local)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Failed to decode reply BSON document."); GOTO (done); } reply_local_initialized = true; if (_mongoc_rpc_parse_command_error (&rpc, error)) { GOTO (done); } ret = true; done: if (reply && reply_local_initialized) { bson_copy_to (&reply_local, reply); bson_destroy (&reply_local); } else if (reply) { bson_init (reply); } _mongoc_buffer_destroy (&buffer); RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_run_ismaster -- * * Run an ismaster command on the given stream. * * Returns: * True if ismaster ran successfully. * * Side effects: * Makes a blocking I/O call and fills out @reply on success, * or @error on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_stream_run_ismaster (mongoc_cluster_t *cluster, mongoc_stream_t *stream, bson_t *reply, bson_error_t *error) { bson_t command; bool ret; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (stream); BSON_ASSERT (reply); BSON_ASSERT (error); bson_init (&command); bson_append_int32 (&command, "ismaster", 8, 1); ret = mongoc_cluster_run_command (cluster, stream, MONGOC_QUERY_SLAVE_OK, "admin", &command, reply, error); bson_destroy (&command); RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_run_ismaster -- * * Run an ismaster command for the given node and handle result. * * Returns: * True if ismaster ran successfully, false otherwise. * * Side effects: * Makes a blocking I/O call. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_run_ismaster (mongoc_cluster_t *cluster, mongoc_cluster_node_t *node) { bson_t reply; bson_error_t error; bson_iter_t iter; int num_fields = 0; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (node); BSON_ASSERT (node->stream); if (!_mongoc_stream_run_ismaster (cluster, node->stream, &reply, &error)) { GOTO (failure); } bson_iter_init (&iter, &reply); while (bson_iter_next (&iter)) { num_fields++; if (strcmp ("maxWriteBatchSize", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; node->max_write_batch_size = bson_iter_int32 (&iter); } else if (strcmp ("minWireVersion", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; node->min_wire_version = bson_iter_int32 (&iter); } else if (strcmp ("maxWireVersion", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; node->max_wire_version = bson_iter_int32 (&iter); } else if (strcmp ("maxBsonObjSize", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; node->max_bson_obj_size = bson_iter_int32 (&iter); } else if (strcmp ("maxMessageSizeBytes", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; node->max_msg_size = bson_iter_int32 (&iter); } } if (num_fields == 0) goto failure; /* TODO: run ismaster through the topology machinery? */ bson_destroy (&reply); return true; failure: bson_destroy (&reply); return false; } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_build_basic_auth_digest -- * * Computes the Basic Authentication digest using the credentials * configured for @cluster and the @nonce provided. * * The result should be freed by the caller using bson_free() when * they are finished with it. * * Returns: * A newly allocated string containing the digest. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static char * _mongoc_cluster_build_basic_auth_digest (mongoc_cluster_t *cluster, const char *nonce) { const char *username; const char *password; char *password_digest; char *password_md5; char *digest_in; char *ret; ENTRY; /* * The following generates the digest to be used for basic authentication * with a MongoDB server. More information on the format can be found * at the following location: * * http://docs.mongodb.org/meta-driver/latest/legacy/ * implement-authentication-in-driver/ */ BSON_ASSERT(cluster); BSON_ASSERT(cluster->uri); username = mongoc_uri_get_username(cluster->uri); password = mongoc_uri_get_password(cluster->uri); password_digest = bson_strdup_printf("%s:mongo:%s", username, password); password_md5 = _mongoc_hex_md5(password_digest); digest_in = bson_strdup_printf("%s%s%s", nonce, username, password_md5); ret = _mongoc_hex_md5(digest_in); bson_free(digest_in); bson_free(password_md5); bson_free(password_digest); RETURN(ret); } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_node_cr -- * * Performs authentication of @node using the credentials provided * when configuring the @cluster instance. * * This is the Challenge-Response mode of authentication. * * Returns: * true if authentication was successful; otherwise false and * @error is set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_auth_node_cr (mongoc_cluster_t *cluster, mongoc_stream_t *stream, bson_error_t *error) { bson_iter_t iter; const char *auth_source; bson_t command = { 0 }; bson_t reply = { 0 }; char *digest; char *nonce; bool ret; ENTRY; BSON_ASSERT(cluster); BSON_ASSERT(stream); if (!(auth_source = mongoc_uri_get_auth_source(cluster->uri)) || (*auth_source == '\0')) { auth_source = "admin"; } /* * To authenticate a node using basic authentication, we need to first * get the nonce from the server. We use that to hash our password which * is sent as a reply to the server. If everything went good we get a * success notification back from the server. */ /* * Execute the getnonce command to fetch the nonce used for generating * md5 digest of our password information. */ bson_init (&command); bson_append_int32 (&command, "getnonce", 8, 1); if (!mongoc_cluster_run_command (cluster, stream, MONGOC_QUERY_SLAVE_OK, auth_source, &command, &reply, error)) { bson_destroy (&command); bson_destroy (&reply); RETURN (false); } bson_destroy (&command); if (!bson_iter_init_find_case (&iter, &reply, "nonce")) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_GETNONCE, "Invalid reply from getnonce"); bson_destroy (&reply); RETURN (false); } /* * Build our command to perform the authentication. */ nonce = bson_iter_dup_utf8(&iter, NULL); digest = _mongoc_cluster_build_basic_auth_digest(cluster, nonce); bson_init(&command); bson_append_int32(&command, "authenticate", 12, 1); bson_append_utf8(&command, "user", 4, mongoc_uri_get_username(cluster->uri), -1); bson_append_utf8(&command, "nonce", 5, nonce, -1); bson_append_utf8(&command, "key", 3, digest, -1); bson_destroy(&reply); bson_free(nonce); bson_free(digest); /* * Execute the authenticate command. mongoc_cluster_run_command * checks for {ok: 1} in the response. */ ret = mongoc_cluster_run_command (cluster, stream, MONGOC_QUERY_SLAVE_OK, auth_source, &command, &reply, error); if (!ret) { /* error->message is already set */ error->domain = MONGOC_ERROR_CLIENT; error->code = MONGOC_ERROR_CLIENT_AUTHENTICATE; } bson_destroy (&command); bson_destroy (&reply); RETURN (ret); } #ifdef MONGOC_ENABLE_SASL /* *-------------------------------------------------------------------------- * * _mongoc_cluster_get_canonicalized_name -- * * Query the node to get the canonicalized name. This may happen if * the node has been accessed via an alias. * * The gssapi code will use this if canonicalizeHostname is true. * * Some underlying layers of krb might do this for us, but they can * be disabled in krb.conf. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_get_canonicalized_name (mongoc_cluster_t *cluster, /* IN */ mongoc_stream_t *node_stream, /* IN */ char *name, /* OUT */ size_t namelen, /* IN */ bson_error_t *error) /* OUT */ { mongoc_stream_t *stream; mongoc_stream_t *tmp; mongoc_socket_t *sock = NULL; char *canonicalized; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (node_stream); BSON_ASSERT (name); /* * Find the underlying socket used in the stream chain. */ for (stream = node_stream; stream;) { if ((tmp = mongoc_stream_get_base_stream (stream))) { stream = tmp; continue; } break; } BSON_ASSERT (stream); if (stream->type == MONGOC_STREAM_SOCKET) { sock = mongoc_stream_socket_get_socket ((mongoc_stream_socket_t *)stream); if (sock) { canonicalized = mongoc_socket_getnameinfo (sock); if (canonicalized) { bson_snprintf (name, namelen, "%s", canonicalized); bson_free (canonicalized); RETURN (true); } } } RETURN (false); } #endif #ifdef MONGOC_ENABLE_SASL /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_node_sasl -- * * Perform authentication for a cluster node using SASL. This is * only supported for GSSAPI at the moment. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * error may be set. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_auth_node_sasl (mongoc_cluster_t *cluster, mongoc_stream_t *stream, const char *hostname, bson_error_t *error) { uint32_t buflen = 0; mongoc_sasl_t sasl; const bson_t *options; bson_iter_t iter; bool ret = false; char real_name [BSON_HOST_NAME_MAX + 1]; const char *service_name; const char *mechanism; const char *tmpstr; uint8_t buf[4096] = { 0 }; bson_t cmd; bson_t reply; int conv_id = 0; BSON_ASSERT (cluster); BSON_ASSERT (stream); options = mongoc_uri_get_options (cluster->uri); _mongoc_sasl_init (&sasl); if ((mechanism = mongoc_uri_get_auth_mechanism (cluster->uri))) { _mongoc_sasl_set_mechanism (&sasl, mechanism); } if (bson_iter_init_find_case (&iter, options, "gssapiservicename") && BSON_ITER_HOLDS_UTF8 (&iter) && (service_name = bson_iter_utf8 (&iter, NULL))) { _mongoc_sasl_set_service_name (&sasl, service_name); } _mongoc_sasl_set_pass (&sasl, mongoc_uri_get_password (cluster->uri)); _mongoc_sasl_set_user (&sasl, mongoc_uri_get_username (cluster->uri)); /* * If the URI requested canonicalizeHostname, we need to resolve the real * hostname for the IP Address and pass that to the SASL layer. Some * underlying GSSAPI layers will do this for us, but can be disabled in * their config (krb.conf). * * This allows the consumer to specify canonicalizeHostname=true in the URI * and have us do that for them. * * See CDRIVER-323 for more information. */ if (bson_iter_init_find_case (&iter, options, "canonicalizeHostname") && BSON_ITER_HOLDS_BOOL (&iter) && bson_iter_bool (&iter)) { if (_mongoc_cluster_get_canonicalized_name (cluster, stream, real_name, sizeof real_name, error)) { _mongoc_sasl_set_service_host (&sasl, real_name); } else { _mongoc_sasl_set_service_host (&sasl, hostname); } } else { _mongoc_sasl_set_service_host (&sasl, hostname); } for (;;) { if (!_mongoc_sasl_step (&sasl, buf, buflen, buf, sizeof buf, &buflen, error)) { goto failure; } bson_init (&cmd); if (sasl.step == 1) { BSON_APPEND_INT32 (&cmd, "saslStart", 1); BSON_APPEND_UTF8 (&cmd, "mechanism", mechanism ? mechanism : "GSSAPI"); bson_append_utf8 (&cmd, "payload", 7, (const char *)buf, buflen); BSON_APPEND_INT32 (&cmd, "autoAuthorize", 1); } else { BSON_APPEND_INT32 (&cmd, "saslContinue", 1); BSON_APPEND_INT32 (&cmd, "conversationId", conv_id); bson_append_utf8 (&cmd, "payload", 7, (const char *)buf, buflen); } MONGOC_INFO ("SASL: authenticating \"%s\" (step %d)", mongoc_uri_get_username (cluster->uri), sasl.step); if (!mongoc_cluster_run_command (cluster, stream, MONGOC_QUERY_SLAVE_OK, "$external", &cmd, &reply, error)) { bson_destroy (&cmd); bson_destroy (&reply); goto failure; } bson_destroy (&cmd); if (bson_iter_init_find (&iter, &reply, "done") && bson_iter_as_bool (&iter)) { bson_destroy (&reply); break; } if (!bson_iter_init_find (&iter, &reply, "conversationId") || !BSON_ITER_HOLDS_INT32 (&iter) || !(conv_id = bson_iter_int32 (&iter)) || !bson_iter_init_find (&iter, &reply, "payload") || !BSON_ITER_HOLDS_UTF8 (&iter)) { MONGOC_INFO ("SASL: authentication failed for \"%s\"", mongoc_uri_get_username (cluster->uri)); bson_destroy (&reply); bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Received invalid SASL reply from MongoDB server."); goto failure; } tmpstr = bson_iter_utf8 (&iter, &buflen); if (buflen > sizeof buf) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "SASL reply from MongoDB is too large."); bson_destroy (&reply); goto failure; } memcpy (buf, tmpstr, buflen); bson_destroy (&reply); } MONGOC_INFO ("SASL: \"%s\" authenticated", mongoc_uri_get_username (cluster->uri)); ret = true; failure: _mongoc_sasl_destroy (&sasl); return ret; } #endif /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_node_plain -- * * Perform SASL PLAIN authentication for @node. We do this manually * instead of using the SASL module because its rather simplistic. * * Returns: * true if successful; otherwise false and error is set. * * Side effects: * error may be set. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_auth_node_plain (mongoc_cluster_t *cluster, mongoc_stream_t *stream, bson_error_t *error) { char buf[4096]; int buflen = 0; const char *username; const char *password; bson_t b = BSON_INITIALIZER; bson_t reply; size_t len; char *str; bool ret; BSON_ASSERT (cluster); BSON_ASSERT (stream); username = mongoc_uri_get_username (cluster->uri); if (!username) { username = ""; } password = mongoc_uri_get_password (cluster->uri); if (!password) { password = ""; } str = bson_strdup_printf ("%c%s%c%s", '\0', username, '\0', password); len = strlen (username) + strlen (password) + 2; buflen = mongoc_b64_ntop ((const uint8_t *) str, len, buf, sizeof buf); bson_free (str); if (buflen == -1) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "failed base64 encoding message"); return false; } BSON_APPEND_INT32 (&b, "saslStart", 1); BSON_APPEND_UTF8 (&b, "mechanism", "PLAIN"); bson_append_utf8 (&b, "payload", 7, (const char *)buf, buflen); BSON_APPEND_INT32 (&b, "autoAuthorize", 1); ret = mongoc_cluster_run_command (cluster, stream, MONGOC_QUERY_SLAVE_OK, "$external", &b, &reply, error); if (!ret) { /* error->message is already set */ error->domain = MONGOC_ERROR_CLIENT; error->code = MONGOC_ERROR_CLIENT_AUTHENTICATE; } bson_destroy (&b); bson_destroy (&reply); return ret; } #ifdef MONGOC_ENABLE_SSL static bool _mongoc_cluster_auth_node_x509 (mongoc_cluster_t *cluster, mongoc_stream_t *stream, bson_error_t *error) { const char *username; bson_t cmd; bson_t reply; bool ret; BSON_ASSERT (cluster); BSON_ASSERT (stream); username = mongoc_uri_get_username (cluster->uri); if (username) { MONGOC_INFO ("X509: got username (%s) from URI", username); } else { if (!cluster->client->ssl_opts.pem_file) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "cannot determine username for " "X-509 authentication."); return false; } if (cluster->client->pem_subject) { username = cluster->client->pem_subject; MONGOC_INFO ("X509: got username (%s) from certificate", username); } } bson_init (&cmd); BSON_APPEND_INT32 (&cmd, "authenticate", 1); BSON_APPEND_UTF8 (&cmd, "mechanism", "MONGODB-X509"); BSON_APPEND_UTF8 (&cmd, "user", username); ret = mongoc_cluster_run_command (cluster, stream, MONGOC_QUERY_SLAVE_OK, "$external", &cmd, &reply, error); if (!ret) { /* error->message is already set */ error->domain = MONGOC_ERROR_CLIENT; error->code = MONGOC_ERROR_CLIENT_AUTHENTICATE; } bson_destroy (&cmd); bson_destroy (&reply); return ret; } #endif #ifdef MONGOC_ENABLE_SSL static bool _mongoc_cluster_auth_node_scram (mongoc_cluster_t *cluster, mongoc_stream_t *stream, bson_error_t *error) { uint32_t buflen = 0; mongoc_scram_t scram; bson_iter_t iter; bool ret = false; const char *tmpstr; const char *auth_source; uint8_t buf[4096] = { 0 }; bson_t cmd; bson_t reply; int conv_id = 0; bson_subtype_t btype; BSON_ASSERT (cluster); BSON_ASSERT (stream); if (!(auth_source = mongoc_uri_get_auth_source(cluster->uri)) || (*auth_source == '\0')) { auth_source = "admin"; } _mongoc_scram_init(&scram); _mongoc_scram_set_pass (&scram, mongoc_uri_get_password (cluster->uri)); _mongoc_scram_set_user (&scram, mongoc_uri_get_username (cluster->uri)); for (;;) { if (!_mongoc_scram_step (&scram, buf, buflen, buf, sizeof buf, &buflen, error)) { goto failure; } bson_init (&cmd); if (scram.step == 1) { BSON_APPEND_INT32 (&cmd, "saslStart", 1); BSON_APPEND_UTF8 (&cmd, "mechanism", "SCRAM-SHA-1"); bson_append_binary (&cmd, "payload", 7, BSON_SUBTYPE_BINARY, buf, buflen); BSON_APPEND_INT32 (&cmd, "autoAuthorize", 1); } else { BSON_APPEND_INT32 (&cmd, "saslContinue", 1); BSON_APPEND_INT32 (&cmd, "conversationId", conv_id); bson_append_binary (&cmd, "payload", 7, BSON_SUBTYPE_BINARY, buf, buflen); } MONGOC_INFO ("SCRAM: authenticating \"%s\" (step %d)", mongoc_uri_get_username (cluster->uri), scram.step); if (!mongoc_cluster_run_command (cluster, stream, MONGOC_QUERY_SLAVE_OK, auth_source, &cmd, &reply, error)) { bson_destroy (&cmd); bson_destroy (&reply); /* error->message is already set */ error->domain = MONGOC_ERROR_CLIENT; error->code = MONGOC_ERROR_CLIENT_AUTHENTICATE; goto failure; } bson_destroy (&cmd); if (bson_iter_init_find (&iter, &reply, "done") && bson_iter_as_bool (&iter)) { bson_destroy (&reply); break; } if (!bson_iter_init_find (&iter, &reply, "conversationId") || !BSON_ITER_HOLDS_INT32 (&iter) || !(conv_id = bson_iter_int32 (&iter)) || !bson_iter_init_find (&iter, &reply, "payload") || !BSON_ITER_HOLDS_BINARY(&iter)) { const char *errmsg = "Received invalid SCRAM reply from MongoDB server."; MONGOC_INFO ("SCRAM: authentication failed for \"%s\"", mongoc_uri_get_username (cluster->uri)); if (bson_iter_init_find (&iter, &reply, "errmsg") && BSON_ITER_HOLDS_UTF8 (&iter)) { errmsg = bson_iter_utf8 (&iter, NULL); } bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "%s", errmsg); bson_destroy (&reply); goto failure; } bson_iter_binary (&iter, &btype, &buflen, (const uint8_t**)&tmpstr); if (buflen > sizeof buf) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "SCRAM reply from MongoDB is too large."); bson_destroy (&reply); goto failure; } memcpy (buf, tmpstr, buflen); bson_destroy (&reply); } MONGOC_INFO ("SCRAM: \"%s\" authenticated", mongoc_uri_get_username (cluster->uri)); ret = true; failure: _mongoc_scram_destroy (&scram); return ret; } #endif /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_node -- * * Authenticate a cluster node depending on the required mechanism. * * Returns: * true if authenticated. false on failure and @error is set. * * Side effects: * @error is set on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_auth_node (mongoc_cluster_t *cluster, mongoc_stream_t *stream, const char *hostname, int32_t max_wire_version, bson_error_t *error) { bool ret = false; const char *mechanism; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (stream); mechanism = mongoc_uri_get_auth_mechanism (cluster->uri); /* Use cached max_wire_version, not value from sd */ if (!mechanism) { if (max_wire_version < WIRE_VERSION_SCRAM_DEFAULT) { mechanism = "MONGODB-CR"; } else { mechanism = "SCRAM-SHA-1"; } } if (0 == strcasecmp (mechanism, "MONGODB-CR")) { ret = _mongoc_cluster_auth_node_cr (cluster, stream, error); } else if (0 == strcasecmp (mechanism, "MONGODB-X509")) { #ifdef MONGOC_ENABLE_SSL ret = _mongoc_cluster_auth_node_x509 (cluster, stream, error); #else bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "The \"%s\" authentication mechanism requires libmongoc built with --enable-ssl", mechanism); #endif } else if (0 == strcasecmp (mechanism, "SCRAM-SHA-1")) { #ifdef MONGOC_ENABLE_SSL ret = _mongoc_cluster_auth_node_scram (cluster, stream, error); #else bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "The \"%s\" authentication mechanism requires libmongoc built with --enable-ssl", mechanism); #endif } else if (0 == strcasecmp (mechanism, "GSSAPI")) { #ifdef MONGOC_ENABLE_SASL ret = _mongoc_cluster_auth_node_sasl (cluster, stream, hostname, error); #else bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "The \"%s\" authentication mechanism requires libmongoc built with --enable-sasl", mechanism); #endif } else if (0 == strcasecmp (mechanism, "PLAIN")) { ret = _mongoc_cluster_auth_node_plain (cluster, stream, error); } else { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Unknown authentication mechanism \"%s\".", mechanism); } if (!ret) { mongoc_counter_auth_failure_inc (); MONGOC_DEBUG("Authentication failed: %s", error->message); } else { mongoc_counter_auth_success_inc (); TRACE("%s", "Authentication succeeded"); } RETURN(ret); } /* *-------------------------------------------------------------------------- * * mongoc_cluster_disconnect_node -- * * Remove a node from the set of nodes. This should be done if * a stream in the set is found to be invalid. * * WARNING: pointers to a disconnected mongoc_cluster_node_t or * its stream are now invalid, be careful of dangling pointers. * * Returns: * None. * * Side effects: * Removes node from cluster's set of nodes, and frees the * mongoc_cluster_node_t if pooled. * *-------------------------------------------------------------------------- */ void mongoc_cluster_disconnect_node (mongoc_cluster_t *cluster, uint32_t server_id) { mongoc_topology_t *topology = cluster->client->topology; ENTRY; if (topology->single_threaded) { mongoc_topology_scanner_node_t *scanner_node; scanner_node = mongoc_topology_scanner_get_node (topology->scanner, server_id); /* might never actually have connected */ if (scanner_node && scanner_node->stream) { mongoc_topology_scanner_node_disconnect (scanner_node, true); EXIT; } EXIT; } else { mongoc_set_rm(cluster->nodes, server_id); } EXIT; } static void _mongoc_cluster_node_destroy (mongoc_cluster_node_t *node) { /* Failure, or Replica Set reconfigure without this node */ mongoc_stream_failed (node->stream); bson_free (node); } static void _mongoc_cluster_node_dtor (void *data_, void *ctx_) { mongoc_cluster_node_t *node = (mongoc_cluster_node_t *)data_; _mongoc_cluster_node_destroy (node); } static mongoc_cluster_node_t * _mongoc_cluster_node_new (mongoc_stream_t *stream) { mongoc_cluster_node_t *node; if (!stream) { return NULL; } node = (mongoc_cluster_node_t *)bson_malloc0(sizeof *node); node->stream = stream; node->timestamp = bson_get_monotonic_time (); node->max_wire_version = MONGOC_DEFAULT_WIRE_VERSION; node->min_wire_version = MONGOC_DEFAULT_WIRE_VERSION; node->max_write_batch_size = MONGOC_DEFAULT_WRITE_BATCH_SIZE; node->max_bson_obj_size = MONGOC_DEFAULT_BSON_OBJ_SIZE; node->max_msg_size = MONGOC_DEFAULT_MAX_MSG_SIZE; return node; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_add_node -- * * Add a new node to this cluster for the given server description. * * NOTE: does NOT check if this server is already in the cluster. * * Returns: * A stream connected to the server, or NULL on failure. * * Side effects: * Adds a cluster node, or sets error on failure. * *-------------------------------------------------------------------------- */ static mongoc_stream_t * _mongoc_cluster_add_node (mongoc_cluster_t *cluster, mongoc_server_description_t *sd, bson_error_t *error /* OUT */) { mongoc_cluster_node_t *cluster_node; mongoc_stream_t *stream; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (!cluster->client->topology->single_threaded); TRACE ("Adding new server to cluster: %s", sd->connection_address); stream = _mongoc_client_create_stream(cluster->client, &sd->host, error); if (!stream) { MONGOC_WARNING ("Failed connection to %s (%s)", sd->connection_address, error->message); RETURN (NULL); } /* take critical fields from a fresh ismaster */ cluster_node = _mongoc_cluster_node_new (stream); if (!_mongoc_cluster_run_ismaster (cluster, cluster_node)) { _mongoc_cluster_node_destroy (cluster_node); MONGOC_WARNING ("Failed connection to %s (ismaster failed)", sd->connection_address); RETURN (NULL); } if (cluster->requires_auth) { if (!_mongoc_cluster_auth_node (cluster, cluster_node->stream, sd->host.host, cluster_node->max_wire_version, error)) { MONGOC_WARNING ("Failed authentication to %s (%s)", sd->connection_address, error->message); _mongoc_cluster_node_destroy (cluster_node); RETURN (NULL); } } mongoc_set_add (cluster->nodes, sd->id, cluster_node); RETURN (stream); } static void node_not_found (mongoc_server_description_t *sd, bson_error_t *error /* OUT */) { if (sd->error.code) { memcpy (error, &sd->error, sizeof *error); } else { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, "Could not find node %s", sd->host.host_and_port); } } static void stream_not_found (mongoc_server_description_t *sd, bson_error_t *error /* OUT */) { if (sd->error.code) { memcpy (error, &sd->error, sizeof *error); } else { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, "Could not find stream for node %s", sd->host.host_and_port); } } static mongoc_server_stream_t * _mongoc_cluster_stream_for_server_description (mongoc_cluster_t *cluster, mongoc_server_description_t *sd, bool reconnect_ok, bson_error_t *error) { mongoc_topology_t *topology; mongoc_server_stream_t *server_stream; ENTRY; topology = cluster->client->topology; /* in the single-threaded use case we share topology's streams */ if (topology->single_threaded) { server_stream = mongoc_cluster_fetch_stream_single (cluster, sd, reconnect_ok, error); } else { server_stream = mongoc_cluster_fetch_stream_pooled (cluster, sd, reconnect_ok, error); } if (!server_stream) { /* failed */ mongoc_cluster_disconnect_node (cluster, sd->id); } RETURN (server_stream); } /* *-------------------------------------------------------------------------- * * mongoc_cluster_stream_for_server -- * * Fetch the stream for @server_id. If @reconnect_ok and there is no * valid stream, attempts to reconnect; if not @reconnect_ok then only * an existing stream can be returned, or NULL. * * Returns: * A mongoc_server_stream_t, or NULL * * Side effects: * May add a node or reconnect one, if @reconnect_ok. * Authenticates the stream if needed. * May set @error. * *-------------------------------------------------------------------------- */ mongoc_server_stream_t * mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster, uint32_t server_id, bool reconnect_ok, bson_error_t *error) { mongoc_topology_t *topology; mongoc_server_description_t *sd; mongoc_server_stream_t *server_stream = NULL; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (server_id); topology = cluster->client->topology; if (!(sd = mongoc_topology_server_by_id (topology, server_id, error))) { RETURN (NULL); } server_stream = _mongoc_cluster_stream_for_server_description (cluster, sd, reconnect_ok, error); if (!server_stream) { /* failed */ mongoc_cluster_disconnect_node (cluster, server_id); mongoc_server_description_destroy (sd); } RETURN (server_stream); } static mongoc_server_stream_t * mongoc_cluster_fetch_stream_single (mongoc_cluster_t *cluster, mongoc_server_description_t *sd, bool reconnect_ok, bson_error_t *error) { mongoc_topology_t *topology; mongoc_stream_t *stream; mongoc_topology_scanner_node_t *scanner_node; int64_t expire_at; bson_t reply; topology = cluster->client->topology; scanner_node = mongoc_topology_scanner_get_node (topology->scanner, sd->id); BSON_ASSERT (scanner_node && !scanner_node->retired); stream = scanner_node->stream; if (!stream) { if (!reconnect_ok) { stream_not_found (sd, error); return NULL; } if (!mongoc_topology_scanner_node_setup (scanner_node, error)) { return NULL; } stream = scanner_node->stream; expire_at = bson_get_monotonic_time() + topology->connect_timeout_msec * 1000; if (!mongoc_stream_wait (stream, expire_at)) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "Failed to connect to target host: '%s'", sd->host.host_and_port); memcpy (&sd->error, error, sizeof sd->error); mongoc_topology_scanner_node_disconnect (scanner_node, true); return NULL; } if (!_mongoc_stream_run_ismaster (cluster, stream, &reply, error)) { mongoc_topology_scanner_node_disconnect (scanner_node, true); return NULL; } /* TODO: run ismaster through the topology machinery? */ bson_destroy (&reply); } /* if stream exists but isn't authed, a disconnect happened */ if (cluster->requires_auth && !scanner_node->has_auth) { /* In single-threaded mode, we can use sd's max_wire_version */ if (!_mongoc_cluster_auth_node (cluster, stream, sd->host.host, sd->max_wire_version, &sd->error)) { memcpy (error, &sd->error, sizeof *error); return NULL; } scanner_node->has_auth = true; } return mongoc_server_stream_new (topology->description.type, sd, stream); } static mongoc_server_stream_t * mongoc_cluster_fetch_stream_pooled (mongoc_cluster_t *cluster, mongoc_server_description_t *sd, bool reconnect_ok, bson_error_t *error) { mongoc_topology_t *topology; mongoc_stream_t *stream; mongoc_cluster_node_t *cluster_node; int64_t timestamp; cluster_node = (mongoc_cluster_node_t *) mongoc_set_get (cluster->nodes, sd->id); topology = cluster->client->topology; if (cluster_node) { BSON_ASSERT (cluster_node->stream); /* existing cluster node, is it outdated? */ timestamp = mongoc_topology_server_timestamp (topology, sd->id); if (timestamp == -1 || cluster_node->timestamp < timestamp) { mongoc_cluster_disconnect_node (cluster, sd->id); } else { /* TODO: thread safety! */ return mongoc_server_stream_new (topology->description.type, sd, cluster_node->stream); } } /* no node, or out of date */ if (!reconnect_ok) { node_not_found (sd, error); return NULL; } stream = _mongoc_cluster_add_node (cluster, sd, error); if (stream) { /* TODO: thread safety! */ return mongoc_server_stream_new (topology->description.type, sd, stream); } else { return NULL; } } /* *-------------------------------------------------------------------------- * * mongoc_cluster_init -- * * Initializes @cluster using the @uri and @client provided. The * @uri is used to determine the "mode" of the cluster. Based on the * uri we can determine if we are connected to a single host, a * replicaSet, or a shardedCluster. * * Returns: * None. * * Side effects: * @cluster is initialized. * *-------------------------------------------------------------------------- */ void mongoc_cluster_init (mongoc_cluster_t *cluster, const mongoc_uri_t *uri, void *client) { ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (uri); memset (cluster, 0, sizeof *cluster); cluster->uri = mongoc_uri_copy(uri); cluster->client = (mongoc_client_t *)client; cluster->requires_auth = (mongoc_uri_get_username(uri) || mongoc_uri_get_auth_mechanism(uri)); cluster->sockettimeoutms = mongoc_uri_get_option_as_int32( uri, "sockettimeoutms", MONGOC_DEFAULT_SOCKETTIMEOUTMS); cluster->socketcheckintervalms = mongoc_uri_get_option_as_int32( uri, "socketcheckintervalms", MONGOC_TOPOLOGY_SOCKET_CHECK_INTERVAL_MS); /* TODO for single-threaded case we don't need this */ cluster->nodes = mongoc_set_new(8, _mongoc_cluster_node_dtor, NULL); _mongoc_array_init (&cluster->iov, sizeof (mongoc_iovec_t)); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_destroy -- * * Clean up after @cluster and destroy all active connections. * All resources for @cluster are released. * * Returns: * None. * * Side effects: * Everything. * *-------------------------------------------------------------------------- */ void mongoc_cluster_destroy (mongoc_cluster_t *cluster) /* INOUT */ { ENTRY; BSON_ASSERT (cluster); mongoc_uri_destroy(cluster->uri); mongoc_set_destroy(cluster->nodes); _mongoc_array_destroy(&cluster->iov); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_stream_for_optype -- * * Internal server selection. * * Returns: * A mongoc_server_stream_t on which you must call * mongoc_server_stream_cleanup, or NULL on failure (sets @error) * * Side effects: * May set @error. * May add new nodes to @cluster->nodes. * *-------------------------------------------------------------------------- */ static mongoc_server_stream_t * _mongoc_cluster_stream_for_optype (mongoc_cluster_t *cluster, mongoc_ss_optype_t optype, const mongoc_read_prefs_t *read_prefs, bson_error_t *error) { mongoc_server_stream_t *server_stream; mongoc_server_description_t *selected_server; mongoc_topology_t *topology = cluster->client->topology; ENTRY; BSON_ASSERT (cluster); /* this is a new copy of the server description */ selected_server = mongoc_topology_select (topology, optype, read_prefs, 15, error); if (!selected_server) { RETURN(NULL); } /* connect or reconnect to server if necessary */ server_stream = _mongoc_cluster_stream_for_server_description ( cluster, selected_server, true /* reconnect_ok */, error); if (!server_stream ) { mongoc_server_description_destroy (selected_server); RETURN (NULL); } RETURN (server_stream); } /* *-------------------------------------------------------------------------- * * mongoc_cluster_stream_for_reads -- * * Internal server selection. * * Returns: * A mongoc_server_stream_t on which you must call * mongoc_server_stream_cleanup, or NULL on failure (sets @error) * * Side effects: * May set @error. * May add new nodes to @cluster->nodes. * *-------------------------------------------------------------------------- */ mongoc_server_stream_t * mongoc_cluster_stream_for_reads (mongoc_cluster_t *cluster, const mongoc_read_prefs_t *read_prefs, bson_error_t *error) { return _mongoc_cluster_stream_for_optype (cluster, MONGOC_SS_READ, read_prefs, error); } /* *-------------------------------------------------------------------------- * * mongoc_cluster_stream_for_writes -- * * Get a stream for write operations. * * Returns: * A mongoc_server_stream_t on which you must call * mongoc_server_stream_cleanup, or NULL on failure (sets @error) * * Side effects: * May set @error. * May add new nodes to @cluster->nodes. * *-------------------------------------------------------------------------- */ mongoc_server_stream_t * mongoc_cluster_stream_for_writes (mongoc_cluster_t *cluster, bson_error_t *error) { return _mongoc_cluster_stream_for_optype (cluster, MONGOC_SS_WRITE, NULL, error); } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_inc_egress_rpc -- * * Helper to increment the counter for a particular RPC based on * it's opcode. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static BSON_INLINE void _mongoc_cluster_inc_egress_rpc (const mongoc_rpc_t *rpc) { mongoc_counter_op_egress_total_inc(); switch (rpc->header.opcode) { case MONGOC_OPCODE_DELETE: mongoc_counter_op_egress_delete_inc(); break; case MONGOC_OPCODE_UPDATE: mongoc_counter_op_egress_update_inc(); break; case MONGOC_OPCODE_INSERT: mongoc_counter_op_egress_insert_inc(); break; case MONGOC_OPCODE_KILL_CURSORS: mongoc_counter_op_egress_killcursors_inc(); break; case MONGOC_OPCODE_GET_MORE: mongoc_counter_op_egress_getmore_inc(); break; case MONGOC_OPCODE_REPLY: mongoc_counter_op_egress_reply_inc(); break; case MONGOC_OPCODE_MSG: mongoc_counter_op_egress_msg_inc(); break; case MONGOC_OPCODE_QUERY: mongoc_counter_op_egress_query_inc(); break; default: BSON_ASSERT(false); break; } } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_inc_ingress_rpc -- * * Helper to increment the counter for a particular RPC based on * it's opcode. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static BSON_INLINE void _mongoc_cluster_inc_ingress_rpc (const mongoc_rpc_t *rpc) { mongoc_counter_op_ingress_total_inc (); switch (rpc->header.opcode) { case MONGOC_OPCODE_DELETE: mongoc_counter_op_ingress_delete_inc (); break; case MONGOC_OPCODE_UPDATE: mongoc_counter_op_ingress_update_inc (); break; case MONGOC_OPCODE_INSERT: mongoc_counter_op_ingress_insert_inc (); break; case MONGOC_OPCODE_KILL_CURSORS: mongoc_counter_op_ingress_killcursors_inc (); break; case MONGOC_OPCODE_GET_MORE: mongoc_counter_op_ingress_getmore_inc (); break; case MONGOC_OPCODE_REPLY: mongoc_counter_op_ingress_reply_inc (); break; case MONGOC_OPCODE_MSG: mongoc_counter_op_ingress_msg_inc (); break; case MONGOC_OPCODE_QUERY: mongoc_counter_op_ingress_query_inc (); break; default: BSON_ASSERT (false); break; } } static bool _mongoc_cluster_min_of_max_obj_size_sds (void *item, void *ctx) { mongoc_server_description_t *sd = (mongoc_server_description_t *)item; int32_t *current_min = (int32_t *)ctx; if (sd->max_bson_obj_size < *current_min) { *current_min = sd->max_bson_obj_size; } return true; } static bool _mongoc_cluster_min_of_max_obj_size_nodes (void *item, void *ctx) { mongoc_cluster_node_t *node = (mongoc_cluster_node_t *)item; int32_t *current_min = (int32_t *)ctx; if (node->max_bson_obj_size < *current_min) { *current_min = node->max_bson_obj_size; } return true; } static bool _mongoc_cluster_min_of_max_msg_size_sds (void *item, void *ctx) { mongoc_server_description_t *sd = (mongoc_server_description_t *)item; int32_t *current_min = (int32_t *)ctx; if (sd->max_msg_size < *current_min) { *current_min = sd->max_msg_size; } return true; } static bool _mongoc_cluster_min_of_max_msg_size_nodes (void *item, void *ctx) { mongoc_cluster_node_t *node = (mongoc_cluster_node_t *)item; int32_t *current_min = (int32_t *)ctx; if (node->max_msg_size < *current_min) { *current_min = node->max_msg_size; } return true; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_get_max_bson_obj_size -- * * Return the minimum max_bson_obj_size across all servers in cluster. * * NOTE: this method uses the topology's mutex. * * Returns: * The minimum max_bson_obj_size. * * Side effects: * None * *-------------------------------------------------------------------------- */ int32_t mongoc_cluster_get_max_bson_obj_size (mongoc_cluster_t *cluster) { int32_t max_bson_obj_size = -1; max_bson_obj_size = MONGOC_DEFAULT_BSON_OBJ_SIZE; if (!cluster->client->topology->single_threaded) { mongoc_set_for_each (cluster->nodes, _mongoc_cluster_min_of_max_obj_size_nodes, &max_bson_obj_size); } else { mongoc_set_for_each (cluster->client->topology->description.servers, _mongoc_cluster_min_of_max_obj_size_sds, &max_bson_obj_size); } return max_bson_obj_size; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_get_max_msg_size -- * * Return the minimum max msg size across all servers in cluster. * * NOTE: this method uses the topology's mutex. * * Returns: * The minimum max_msg_size * * Side effects: * None * *-------------------------------------------------------------------------- */ int32_t mongoc_cluster_get_max_msg_size (mongoc_cluster_t *cluster) { int32_t max_msg_size = MONGOC_DEFAULT_MAX_MSG_SIZE; if (!cluster->client->topology->single_threaded) { mongoc_set_for_each (cluster->nodes, _mongoc_cluster_min_of_max_msg_size_nodes, &max_msg_size); } else { mongoc_set_for_each (cluster->client->topology->description.servers, _mongoc_cluster_min_of_max_msg_size_sds, &max_msg_size); } return max_msg_size; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_node_min_wire_version -- * * Return the min wire version for the given server. * * Returns: * Min wire version, or -1 if server is not found. * *-------------------------------------------------------------------------- */ int32_t mongoc_cluster_node_min_wire_version (mongoc_cluster_t *cluster, uint32_t server_id) { mongoc_server_description_t *sd; mongoc_cluster_node_t *node; if (cluster->client->topology->single_threaded) { if ((sd = mongoc_topology_description_server_by_id ( &cluster->client->topology->description, server_id, NULL))) { return sd->min_wire_version; } } else { if((node = (mongoc_cluster_node_t *)mongoc_set_get(cluster->nodes, server_id))) { return node->min_wire_version; } } return -1; } static bool _mongoc_cluster_check_interval (mongoc_cluster_t *cluster, uint32_t server_id, bson_error_t *error) { mongoc_topology_t *topology; mongoc_topology_scanner_node_t *scanner_node; mongoc_server_description_t *sd; mongoc_stream_t *stream; int64_t now; int64_t before_ismaster; bson_t command; bson_t reply; bool r; topology = cluster->client->topology; if (!topology->single_threaded) { return true; } scanner_node = mongoc_topology_scanner_get_node (topology->scanner, server_id); if (!scanner_node) { return false; } BSON_ASSERT (!scanner_node->retired); stream = scanner_node->stream; if (!stream) { return false; } now = bson_get_monotonic_time (); if (scanner_node->last_used + (1000 * CHECK_CLOSED_DURATION_MSEC) < now) { if (mongoc_stream_check_closed (stream)) { mongoc_cluster_disconnect_node (cluster, server_id); return false; } } if (scanner_node->last_used + (1000 * cluster->socketcheckintervalms) < now) { bson_init (&command); BSON_APPEND_INT32 (&command, "ismaster", 1); before_ismaster = now; r = mongoc_cluster_run_command (cluster, stream, MONGOC_QUERY_SLAVE_OK, "admin", &command, &reply, error); now = bson_get_monotonic_time (); bson_destroy (&command); if (r) { sd = mongoc_topology_description_server_by_id (&topology->description, server_id, NULL); if (!sd) { bson_destroy (&reply); return false; } mongoc_topology_description_handle_ismaster ( &topology->description, sd, &reply, (now - before_ismaster) / 1000, /* RTT_MS */ error); bson_destroy (&reply); } else { bson_destroy (&reply); return false; } } return true; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_sendv_to_server -- * * Sends the given RPCs to the given server. * * Returns: * True if successful. * * Side effects: * @rpcs may be mutated and should be considered invalid after calling * this method. * * @error may be set. * *-------------------------------------------------------------------------- */ bool mongoc_cluster_sendv_to_server (mongoc_cluster_t *cluster, mongoc_rpc_t *rpcs, size_t rpcs_len, mongoc_server_stream_t *server_stream, const mongoc_write_concern_t *write_concern, bson_error_t *error) { uint32_t server_id; mongoc_iovec_t *iov; mongoc_topology_scanner_node_t *scanner_node; const bson_t *b; mongoc_rpc_t gle; size_t iovcnt; size_t i; bool need_gle; char cmdname[140]; int32_t max_msg_size; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (rpcs); BSON_ASSERT (rpcs_len); BSON_ASSERT (server_stream); server_id = server_stream->sd->id; if (cluster->client->in_exhaust) { bson_set_error(error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_IN_EXHAUST, "A cursor derived from this client is in exhaust."); RETURN(false); } if (! write_concern) { write_concern = cluster->client->write_concern; } if (!_mongoc_cluster_check_interval (cluster, server_stream->sd->id, error)) { RETURN (false); } _mongoc_array_clear(&cluster->iov); /* * TODO: We can probably remove the need for sendv and just do send since * we support write concerns now. Also, we clobber our getlasterror on * each subsequent mutation. It's okay, since it comes out correct anyway, * just useless work (and technically the request_id changes). */ for (i = 0; i < rpcs_len; i++) { _mongoc_cluster_inc_egress_rpc (&rpcs[i]); rpcs[i].header.request_id = ++cluster->request_id; need_gle = _mongoc_rpc_needs_gle(&rpcs[i], write_concern); _mongoc_rpc_gather (&rpcs[i], &cluster->iov); max_msg_size = mongoc_server_stream_max_msg_size (server_stream); if (rpcs[i].header.msg_len > max_msg_size) { bson_set_error(error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_TOO_BIG, "Attempted to send an RPC larger than the " "max allowed message size. Was %u, allowed %u.", rpcs[i].header.msg_len, max_msg_size); RETURN(false); } if (need_gle) { gle.query.msg_len = 0; gle.query.request_id = ++cluster->request_id; gle.query.response_to = 0; gle.query.opcode = MONGOC_OPCODE_QUERY; gle.query.flags = MONGOC_QUERY_NONE; switch (rpcs[i].header.opcode) { case MONGOC_OPCODE_INSERT: DB_AND_CMD_FROM_COLLECTION(cmdname, rpcs[i].insert.collection); break; case MONGOC_OPCODE_DELETE: DB_AND_CMD_FROM_COLLECTION(cmdname, rpcs[i].delete_.collection); break; case MONGOC_OPCODE_UPDATE: DB_AND_CMD_FROM_COLLECTION(cmdname, rpcs[i].update.collection); break; default: BSON_ASSERT(false); DB_AND_CMD_FROM_COLLECTION(cmdname, "admin.$cmd"); break; } gle.query.collection = cmdname; gle.query.skip = 0; gle.query.n_return = 1; b = _mongoc_write_concern_get_gle((mongoc_write_concern_t *)write_concern); gle.query.query = bson_get_data(b); gle.query.fields = NULL; _mongoc_rpc_gather(&gle, &cluster->iov); _mongoc_rpc_swab_to_le(&gle); } _mongoc_rpc_swab_to_le(&rpcs[i]); } iov = (mongoc_iovec_t *)cluster->iov.data; iovcnt = cluster->iov.len; BSON_ASSERT (cluster->iov.len); if (!_mongoc_stream_writev_full (server_stream->stream, iov, iovcnt, cluster->sockettimeoutms, error)) { RETURN (false); } if (cluster->client->topology->single_threaded) { scanner_node = mongoc_topology_scanner_get_node (cluster->client->topology->scanner, server_id); if (scanner_node) { scanner_node->last_used = bson_get_monotonic_time (); } } RETURN (true); } /* *-------------------------------------------------------------------------- * * mongoc_cluster_try_recv -- * * Tries to receive the next event from the MongoDB server. * The contents are loaded into @buffer and then * scattered into the @rpc structure. @rpc is valid as long as * @buffer contains the contents read into it. * * Callers that can optimize a reuse of @buffer should do so. It * can save many memory allocations. * * Returns: * True if successful. * * Side effects: * @rpc is set on success, @error on failure. * @buffer will be filled with the input data. * *-------------------------------------------------------------------------- */ bool mongoc_cluster_try_recv (mongoc_cluster_t *cluster, mongoc_rpc_t *rpc, mongoc_buffer_t *buffer, mongoc_server_stream_t *server_stream, bson_error_t *error) { uint32_t server_id; int32_t msg_len; int32_t max_msg_size; off_t pos; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (rpc); BSON_ASSERT (buffer); BSON_ASSERT (server_stream); server_id = server_stream->sd->id; TRACE ("Waiting for reply from server_id \"%u\"", server_id); /* * Buffer the message length to determine how much more to read. */ pos = buffer->len; if (!_mongoc_buffer_append_from_stream (buffer, server_stream->stream, 4, cluster->sockettimeoutms, error)) { MONGOC_DEBUG("Could not read 4 bytes, stream probably closed or timed out"); mongoc_counter_protocol_ingress_error_inc (); mongoc_cluster_disconnect_node(cluster, server_id); RETURN (false); } /* * Read the msg length from the buffer. */ memcpy (&msg_len, &buffer->data[buffer->off + pos], 4); msg_len = BSON_UINT32_FROM_LE (msg_len); max_msg_size = mongoc_server_stream_max_msg_size (server_stream); if ((msg_len < 16) || (msg_len > max_msg_size)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Corrupt or malicious reply received."); mongoc_cluster_disconnect_node(cluster, server_id); mongoc_counter_protocol_ingress_error_inc (); RETURN (false); } /* * Read the rest of the message from the stream. */ if (!_mongoc_buffer_append_from_stream (buffer, server_stream->stream, msg_len - 4, cluster->sockettimeoutms, error)) { mongoc_cluster_disconnect_node (cluster, server_id); mongoc_counter_protocol_ingress_error_inc (); RETURN (false); } /* * Scatter the buffer into the rpc structure. */ if (!_mongoc_rpc_scatter (rpc, &buffer->data[buffer->off + pos], msg_len)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Failed to decode reply from server."); mongoc_cluster_disconnect_node (cluster, server_id); mongoc_counter_protocol_ingress_error_inc (); RETURN (false); } _mongoc_rpc_swab_from_le (rpc); _mongoc_cluster_inc_ingress_rpc (rpc); RETURN(true); } libmongoc-1.3.1/src/mongoc/mongoc-collection-private.h000066400000000000000000000042751264720626300230120ustar00rootroot00000000000000/* * Copyright 2013-2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_COLLECTION_PRIVATE_H #define MONGOC_COLLECTION_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-buffer-private.h" #include "mongoc-client.h" BSON_BEGIN_DECLS struct _mongoc_collection_t { mongoc_client_t *client; char ns[128]; uint32_t nslen; char db[128]; char collection[128]; uint32_t collectionlen; mongoc_buffer_t buffer; mongoc_read_prefs_t *read_prefs; mongoc_read_concern_t *read_concern; mongoc_write_concern_t *write_concern; bson_t *gle; }; mongoc_collection_t *_mongoc_collection_new (mongoc_client_t *client, const char *db, const char *collection, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern); mongoc_cursor_t *_mongoc_collection_find_indexes_legacy (mongoc_collection_t *collection, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_COLLECTION_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-collection.c000066400000000000000000002110511264720626300213250ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "mongoc-bulk-operation.h" #include "mongoc-bulk-operation-private.h" #include "mongoc-client-private.h" #include "mongoc-find-and-modify-private.h" #include "mongoc-find-and-modify.h" #include "mongoc-collection.h" #include "mongoc-collection-private.h" #include "mongoc-cursor-private.h" #include "mongoc-cursor-cursorid-private.h" #include "mongoc-cursor-array-private.h" #include "mongoc-error.h" #include "mongoc-index.h" #include "mongoc-log.h" #include "mongoc-trace.h" #include "mongoc-read-concern-private.h" #include "mongoc-write-concern-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "collection" #define _BSON_APPEND_WRITE_CONCERN(_bson, _write_concern) \ do { \ const bson_t *write_concern_bson; \ mongoc_write_concern_t *write_concern_copy = NULL; \ if (_write_concern->frozen) { \ write_concern_bson = _mongoc_write_concern_get_bson (_write_concern); \ } else { \ /* _mongoc_write_concern_get_bson will freeze the write_concern */ \ write_concern_copy = mongoc_write_concern_copy (_write_concern); \ write_concern_bson = _mongoc_write_concern_get_bson (write_concern_copy); \ } \ BSON_APPEND_DOCUMENT (_bson, "writeConcern", write_concern_bson); \ if (write_concern_copy) { \ mongoc_write_concern_destroy (write_concern_copy); \ } \ } while(0); \ static bool validate_name (const char *str) { const char *c; if (str && *str) { for (c = str; *c; c++) { switch (*c) { case '/': case '\\': case '.': case '"': case '*': case '<': case '>': case ':': case '|': case '?': return false; default: break; } } return ((0 != strcmp (str, "oplog.$main")) && (0 != strcmp (str, "$cmd"))); } return false; } static mongoc_cursor_t * _mongoc_collection_cursor_new (mongoc_collection_t *collection, mongoc_query_flags_t flags) { return _mongoc_cursor_new (collection->client, collection->ns, flags, 0, /* skip */ 0, /* limit */ 0, /* batch_size */ false, /* is_command */ NULL, /* query */ NULL, /* fields */ NULL, /* read prefs */ NULL); /* read concern */ } static void _mongoc_collection_write_command_execute (mongoc_write_command_t *command, const mongoc_collection_t *collection, const mongoc_write_concern_t *write_concern, mongoc_write_result_t *result) { mongoc_server_stream_t *server_stream; ENTRY; server_stream = mongoc_cluster_stream_for_writes (&collection->client->cluster, &result->error); if (!server_stream) { /* result->error has been filled out */ EXIT; } _mongoc_write_command_execute (command, collection->client, server_stream, collection->db, collection->collection, write_concern, 0 /* offset */, result); mongoc_server_stream_cleanup (server_stream); EXIT; } /* *-------------------------------------------------------------------------- * * _mongoc_collection_new -- * * INTERNAL API * * Create a new mongoc_collection_t structure for the given client. * * @client must remain valid during the lifetime of this structure. * @db is the db name of the collection. * @collection is the name of the collection. * @read_prefs is the default read preferences to apply or NULL. * @read_concern is the default read concern to apply or NULL. * @write_concern is the default write concern to apply or NULL. * * Returns: * A newly allocated mongoc_collection_t that should be freed with * mongoc_collection_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_collection_t * _mongoc_collection_new (mongoc_client_t *client, const char *db, const char *collection, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern) { mongoc_collection_t *col; ENTRY; BSON_ASSERT (client); BSON_ASSERT (db); BSON_ASSERT (collection); col = (mongoc_collection_t *)bson_malloc0(sizeof *col); col->client = client; col->write_concern = write_concern ? mongoc_write_concern_copy(write_concern) : mongoc_write_concern_new(); col->read_concern = read_concern ? mongoc_read_concern_copy(read_concern) : mongoc_read_concern_new(); col->read_prefs = read_prefs ? mongoc_read_prefs_copy(read_prefs) : mongoc_read_prefs_new(MONGOC_READ_PRIMARY); bson_snprintf (col->ns, sizeof col->ns, "%s.%s", db, collection); bson_snprintf (col->db, sizeof col->db, "%s", db); bson_snprintf (col->collection, sizeof col->collection, "%s", collection); col->collectionlen = (uint32_t)strlen(col->collection); col->nslen = (uint32_t)strlen(col->ns); _mongoc_buffer_init(&col->buffer, NULL, 0, NULL, NULL); col->gle = NULL; RETURN(col); } /* *-------------------------------------------------------------------------- * * mongoc_collection_destroy -- * * Release resources associated with @collection and frees the * structure. * * Returns: * None. * * Side effects: * Everything. * *-------------------------------------------------------------------------- */ void mongoc_collection_destroy (mongoc_collection_t *collection) /* IN */ { ENTRY; BSON_ASSERT (collection); bson_clear (&collection->gle); _mongoc_buffer_destroy(&collection->buffer); if (collection->read_prefs) { mongoc_read_prefs_destroy(collection->read_prefs); collection->read_prefs = NULL; } if (collection->read_concern) { mongoc_read_concern_destroy(collection->read_concern); collection->read_concern = NULL; } if (collection->write_concern) { mongoc_write_concern_destroy(collection->write_concern); collection->write_concern = NULL; } bson_free(collection); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_collection_copy -- * * Returns a copy of @collection that needs to be freed by calling * mongoc_collection_destroy. * * Returns: * A copy of this collection. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_collection_t * mongoc_collection_copy (mongoc_collection_t *collection) /* IN */ { ENTRY; BSON_ASSERT (collection); RETURN(_mongoc_collection_new(collection->client, collection->db, collection->collection, collection->read_prefs, collection->read_concern, collection->write_concern)); } /* *-------------------------------------------------------------------------- * * mongoc_collection_aggregate -- * * Send an "aggregate" command to the MongoDB server. * * This varies it's behavior based on the wire version. If we're on * wire_version > 0, we use the new aggregate command, which returns a * database cursor. On wire_version == 0, we create synthetic cursor on * top of the array returned in result. * * This function will always return a new mongoc_cursor_t that should * be freed with mongoc_cursor_destroy(). * * The cursor may fail once iterated upon, so check * mongoc_cursor_error() if mongoc_cursor_next() returns false. * * See http://docs.mongodb.org/manual/aggregation/ for more * information on how to build aggregation pipelines. * * Requires: * MongoDB >= 2.1.0 * * Parameters: * @flags: bitwise or of mongoc_query_flags_t or 0. * @pipeline: A bson_t containing the pipeline request. @pipeline * will be sent as an array type in the request. * @options: A bson_t containing aggregation options, such as * bypassDocumentValidation (used with $out pipeline), * maxTimeMS (declaring maximum server execution time) and * explain (return information on the processing of the pipeline). * @read_prefs: Optional read preferences for the command. * * Returns: * A newly allocated mongoc_cursor_t that should be freed with * mongoc_cursor_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_cursor_t * mongoc_collection_aggregate (mongoc_collection_t *collection, /* IN */ mongoc_query_flags_t flags, /* IN */ const bson_t *pipeline, /* IN */ const bson_t *options, /* IN */ const mongoc_read_prefs_t *read_prefs) /* IN */ { mongoc_server_description_t *selected_server; mongoc_cursor_t *cursor; bson_iter_t iter; bson_t command; bson_t child; int32_t batch_size = 0; bool use_cursor; ENTRY; BSON_ASSERT (collection); BSON_ASSERT (pipeline); bson_init (&command); if (!read_prefs) { read_prefs = collection->read_prefs; } cursor = _mongoc_collection_cursor_new (collection, flags); selected_server = mongoc_topology_select(collection->client->topology, MONGOC_SS_READ, read_prefs, 15, &cursor->error); if (!selected_server) { GOTO (done); } cursor->hint = selected_server->id; use_cursor = selected_server->max_wire_version >= WIRE_VERSION_AGG_CURSOR; BSON_APPEND_UTF8 (&command, "aggregate", collection->collection); /* * The following will allow @pipeline to be either an array of * items for the pipeline, or {"pipeline": [...]}. */ if (bson_iter_init_find (&iter, pipeline, "pipeline") && BSON_ITER_HOLDS_ARRAY (&iter)) { if (!bson_append_iter (&command, "pipeline", 8, &iter)) { bson_set_error (&cursor->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Failed to append \"pipeline\" to create command."); GOTO (done); } } else { BSON_APPEND_ARRAY (&command, "pipeline", pipeline); } /* for newer version, we include a cursor subdocument */ if (use_cursor) { bson_append_document_begin (&command, "cursor", 6, &child); if (options && bson_iter_init (&iter, options)) { while (bson_iter_next (&iter)) { if (BSON_ITER_IS_KEY (&iter, "batchSize") && (BSON_ITER_HOLDS_INT32 (&iter) || BSON_ITER_HOLDS_INT64 (&iter) || BSON_ITER_HOLDS_DOUBLE (&iter))) { batch_size = (int32_t)bson_iter_as_int64 (&iter); BSON_APPEND_INT32 (&child, "batchSize", batch_size); } } } bson_append_document_end (&command, &child); } if (options && bson_iter_init (&iter, options)) { while (bson_iter_next (&iter)) { if (! (BSON_ITER_IS_KEY (&iter, "batchSize") || BSON_ITER_IS_KEY (&iter, "cursor"))) { if (!bson_append_iter (&command, bson_iter_key (&iter), -1, &iter)) { bson_set_error (&cursor->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Failed to append \"batchSize\" or \"cursor\" to create command."); GOTO (done); } } } } if (collection->read_concern->level != NULL) { const bson_t *read_concern_bson; if (selected_server->max_wire_version < WIRE_VERSION_READ_CONCERN) { bson_set_error (&cursor->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support readConcern"); GOTO (done); } read_concern_bson = _mongoc_read_concern_get_bson (collection->read_concern); BSON_APPEND_DOCUMENT (&command, "readConcern", read_concern_bson); } if (use_cursor) { _mongoc_cursor_cursorid_init (cursor, &command); } else { /* for older versions we get an array that we can create a synthetic * cursor on top of */ _mongoc_cursor_array_init (cursor, &command, "result"); } done: if (selected_server) { mongoc_server_description_destroy (selected_server); } bson_destroy(&command); /* we always return the cursor, even if it fails; users can detect the * failure on performing a cursor operation. see CDRIVER-880. */ RETURN (cursor); } /* *-------------------------------------------------------------------------- * * mongoc_collection_find -- * * Performs a query against the configured MongoDB server. If @read_prefs * is provided, it will be used to locate a MongoDB node in the cluster * to deliver the query to. * * @flags may be bitwise-or'd flags or MONGOC_QUERY_NONE. * * @skip may contain the number of documents to skip before returning the * matching document. * * @limit may contain the maximum number of documents that may be * returned. * * This function will always return a cursor, with the exception of * invalid API use. * * Parameters: * @collection: A mongoc_collection_t. * @flags: A bitwise or of mongoc_query_flags_t. * @skip: The number of documents to skip. * @limit: The maximum number of items. * @batch_size: The batch size * @query: The query to locate matching documents. * @fields: The fields to return, or NULL for all fields. * @read_prefs: Read preferences to choose cluster node. * * Returns: * A newly allocated mongoc_cursor_t that should be freed with * mongoc_cursor_destroy(). * * The client used by mongoc_collection_t must be valid for the * lifetime of the resulting mongoc_cursor_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_cursor_t * mongoc_collection_find (mongoc_collection_t *collection, /* IN */ mongoc_query_flags_t flags, /* IN */ uint32_t skip, /* IN */ uint32_t limit, /* IN */ uint32_t batch_size, /* IN */ const bson_t *query, /* IN */ const bson_t *fields, /* IN */ const mongoc_read_prefs_t *read_prefs) /* IN */ { BSON_ASSERT (collection); BSON_ASSERT (query); bson_clear (&collection->gle); if (!read_prefs) { read_prefs = collection->read_prefs; } return _mongoc_cursor_new (collection->client, collection->ns, flags, skip, limit, batch_size, false, query, fields, read_prefs, collection->read_concern); } /* *-------------------------------------------------------------------------- * * mongoc_collection_command -- * * Executes a command on a cluster node matching @read_prefs. If * @read_prefs is not provided, it will be run on the primary node. * * This function will always return a mongoc_cursor_t. * * Parameters: * @collection: A mongoc_collection_t. * @flags: Bitwise-or'd flags for command. * @skip: Number of documents to skip, typically 0. * @limit : Number of documents to return * @batch_size : Batch size * @query: The command to execute. * @fields: The fields to return, or NULL. * @read_prefs: Command read preferences or NULL. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_cursor_t * mongoc_collection_command (mongoc_collection_t *collection, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) { char ns[MONGOC_NAMESPACE_MAX]; BSON_ASSERT (collection); BSON_ASSERT (query); if (!read_prefs) { read_prefs = collection->read_prefs; } bson_clear (&collection->gle); if (NULL == strstr (collection->collection, "$cmd")) { bson_snprintf (ns, sizeof ns, "%s", collection->db); } else { bson_snprintf (ns, sizeof ns, "%s.%s", collection->db, collection->collection); } return mongoc_client_command (collection->client, ns, flags, skip, limit, batch_size, query, fields, read_prefs); } bool mongoc_collection_command_simple (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error) { BSON_ASSERT (collection); BSON_ASSERT (command); bson_clear (&collection->gle); return mongoc_client_command_simple (collection->client, collection->db, command, read_prefs, reply, error); } /* *-------------------------------------------------------------------------- * * mongoc_collection_count -- * * Count the number of documents matching @query. * * Parameters: * @flags: A mongoc_query_flags_t describing the query flags or 0. * @query: The query to perform or NULL for {}. * @skip: The $skip to perform within the query or 0. * @limit: The $limit to perform within the query or 0. * @read_prefs: desired read preferences or NULL. * @error: A location for an error or NULL. * * Returns: * -1 on failure; otherwise the number of matching documents. * * Side effects: * @error is set upon failure if non-NULL. * *-------------------------------------------------------------------------- */ int64_t mongoc_collection_count (mongoc_collection_t *collection, /* IN */ mongoc_query_flags_t flags, /* IN */ const bson_t *query, /* IN */ int64_t skip, /* IN */ int64_t limit, /* IN */ const mongoc_read_prefs_t *read_prefs, /* IN */ bson_error_t *error) /* OUT */ { return mongoc_collection_count_with_opts ( collection, flags, query, skip, limit, NULL, read_prefs, error); } int64_t mongoc_collection_count_with_opts (mongoc_collection_t *collection, /* IN */ mongoc_query_flags_t flags, /* IN */ const bson_t *query, /* IN */ int64_t skip, /* IN */ int64_t limit, /* IN */ const bson_t *opts, /* IN */ const mongoc_read_prefs_t *read_prefs, /* IN */ bson_error_t *error) /* OUT */ { mongoc_server_stream_t *server_stream; mongoc_cluster_t *cluster; bson_iter_t iter; int64_t ret = -1; bool success; bson_t reply; bson_t cmd; bson_t q; ENTRY; cluster = &collection->client->cluster; server_stream = mongoc_cluster_stream_for_writes (cluster, error); if (!server_stream) { RETURN (-1); } BSON_ASSERT (collection); bson_init(&cmd); bson_append_utf8(&cmd, "count", 5, collection->collection, collection->collectionlen); if (query) { bson_append_document(&cmd, "query", 5, query); } else { bson_init(&q); bson_append_document(&cmd, "query", 5, &q); bson_destroy(&q); } if (limit) { bson_append_int64(&cmd, "limit", 5, limit); } if (skip) { bson_append_int64(&cmd, "skip", 4, skip); } if (collection->read_concern->level != NULL) { const bson_t *read_concern_bson; if (server_stream->sd->max_wire_version < WIRE_VERSION_READ_CONCERN) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support readConcern"); bson_destroy (&cmd); mongoc_server_stream_cleanup (server_stream); RETURN (-1); } read_concern_bson = _mongoc_read_concern_get_bson (collection->read_concern); BSON_APPEND_DOCUMENT (&cmd, "readConcern", read_concern_bson); } if (opts) { bson_concat(&cmd, opts); } success = mongoc_cluster_run_command (cluster, server_stream->stream, MONGOC_QUERY_SLAVE_OK, collection->db, &cmd, &reply, error); if (success && bson_iter_init_find(&iter, &reply, "n")) { ret = bson_iter_as_int64(&iter); } bson_destroy (&reply); bson_destroy (&cmd); mongoc_server_stream_cleanup (server_stream); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_collection_drop -- * * Request the MongoDB server drop the collection. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @error is set upon failure. * *-------------------------------------------------------------------------- */ bool mongoc_collection_drop (mongoc_collection_t *collection, /* IN */ bson_error_t *error) /* OUT */ { bool ret; bson_t cmd; BSON_ASSERT (collection); bson_init(&cmd); bson_append_utf8(&cmd, "drop", 4, collection->collection, collection->collectionlen); ret = mongoc_collection_command_simple(collection, &cmd, NULL, NULL, error); bson_destroy(&cmd); return ret; } /* *-------------------------------------------------------------------------- * * mongoc_collection_drop_index -- * * Request the MongoDB server drop the named index. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @error is setup upon failure if non-NULL. * *-------------------------------------------------------------------------- */ bool mongoc_collection_drop_index (mongoc_collection_t *collection, /* IN */ const char *index_name, /* IN */ bson_error_t *error) /* OUT */ { bool ret; bson_t cmd; BSON_ASSERT (collection); BSON_ASSERT (index_name); bson_init(&cmd); bson_append_utf8(&cmd, "dropIndexes", -1, collection->collection, collection->collectionlen); bson_append_utf8(&cmd, "index", -1, index_name, -1); ret = mongoc_collection_command_simple(collection, &cmd, NULL, NULL, error); bson_destroy(&cmd); return ret; } char * mongoc_collection_keys_to_index_string (const bson_t *keys) { bson_string_t *s; bson_iter_t iter; int i = 0; BSON_ASSERT (keys); if (!bson_iter_init (&iter, keys)) { return NULL; } s = bson_string_new (NULL); while (bson_iter_next (&iter)) { /* Index type can be specified as a string ("2d") or as an integer representing direction */ if (bson_iter_type(&iter) == BSON_TYPE_UTF8) { bson_string_append_printf (s, (i++ ? "_%s_%s" : "%s_%s"), bson_iter_key (&iter), bson_iter_utf8 (&iter, NULL)); } else { bson_string_append_printf (s, (i++ ? "_%s_%d" : "%s_%d"), bson_iter_key (&iter), bson_iter_int32 (&iter)); } } return bson_string_free (s, false); } /* *-------------------------------------------------------------------------- * * _mongoc_collection_create_index_legacy -- * * Request the MongoDB server create the named index. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @error is setup upon failure if non-NULL. * *-------------------------------------------------------------------------- */ static bool _mongoc_collection_create_index_legacy (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, bson_error_t *error) { const mongoc_index_opt_t *def_opt; mongoc_collection_t *col; bool ret; bson_t insert; char *name; BSON_ASSERT (collection); /* * TODO: this is supposed to be cached and cheap... make it that way */ def_opt = mongoc_index_opt_get_default (); opt = opt ? opt : def_opt; if (!opt->is_initialized) { MONGOC_WARNING("Options have not yet been initialized"); return false; } bson_init (&insert); bson_append_document (&insert, "key", -1, keys); bson_append_utf8 (&insert, "ns", -1, collection->ns, -1); if (opt->background != def_opt->background) { bson_append_bool (&insert, "background", -1, opt->background); } if (opt->unique != def_opt->unique) { bson_append_bool (&insert, "unique", -1, opt->unique); } if (opt->name != def_opt->name) { bson_append_utf8 (&insert, "name", -1, opt->name, -1); } else { name = mongoc_collection_keys_to_index_string(keys); if (!name) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Cannot generate index name from invalid `keys` argument" ); bson_destroy (&insert); return false; } bson_append_utf8 (&insert, "name", -1, name, -1); bson_free (name); } if (opt->drop_dups != def_opt->drop_dups) { bson_append_bool (&insert, "dropDups", -1, opt->drop_dups); } if (opt->sparse != def_opt->sparse) { bson_append_bool (&insert, "sparse", -1, opt->sparse); } if (opt->expire_after_seconds != def_opt->expire_after_seconds) { bson_append_int32 (&insert, "expireAfterSeconds", -1, opt->expire_after_seconds); } if (opt->v != def_opt->v) { bson_append_int32 (&insert, "v", -1, opt->v); } if (opt->weights != def_opt->weights) { bson_append_document (&insert, "weights", -1, opt->weights); } if (opt->default_language != def_opt->default_language) { bson_append_utf8 (&insert, "default_language", -1, opt->default_language, -1); } if (opt->language_override != def_opt->language_override) { bson_append_utf8 (&insert, "language_override", -1, opt->language_override, -1); } col = mongoc_client_get_collection (collection->client, collection->db, "system.indexes"); ret = mongoc_collection_insert (col, (mongoc_insert_flags_t)MONGOC_INSERT_NO_VALIDATE, &insert, NULL, error); mongoc_collection_destroy(col); bson_destroy (&insert); return ret; } bool mongoc_collection_create_index (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, bson_error_t *error) { const mongoc_index_opt_t *def_opt; const mongoc_index_opt_geo_t *def_geo; bson_error_t local_error; const char *name; bson_t cmd = BSON_INITIALIZER; bson_t ar; bson_t doc; bson_t reply; bson_t storage_doc; bson_t wt_doc; const mongoc_index_opt_geo_t *geo_opt; const mongoc_index_opt_storage_t *storage_opt; const mongoc_index_opt_wt_t *wt_opt; char *alloc_name = NULL; bool ret = false; BSON_ASSERT (collection); BSON_ASSERT (keys); def_opt = mongoc_index_opt_get_default (); opt = opt ? opt : def_opt; /* * Generate the key name if it was not provided. */ name = (opt->name != def_opt->name) ? opt->name : NULL; if (!name) { alloc_name = mongoc_collection_keys_to_index_string (keys); if (alloc_name) { name = alloc_name; } else { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Cannot generate index name from invalid `keys` argument" ); bson_destroy (&cmd); return false; } } /* * Build our createIndexes command to send to the server. */ BSON_APPEND_UTF8 (&cmd, "createIndexes", collection->collection); bson_append_array_begin (&cmd, "indexes", 7, &ar); bson_append_document_begin (&ar, "0", 1, &doc); BSON_APPEND_DOCUMENT (&doc, "key", keys); BSON_APPEND_UTF8 (&doc, "name", name); if (opt->background) { BSON_APPEND_BOOL (&doc, "background", true); } if (opt->unique) { BSON_APPEND_BOOL (&doc, "unique", true); } if (opt->drop_dups) { BSON_APPEND_BOOL (&doc, "dropDups", true); } if (opt->sparse) { BSON_APPEND_BOOL (&doc, "sparse", true); } if (opt->expire_after_seconds != def_opt->expire_after_seconds) { BSON_APPEND_INT32 (&doc, "expireAfterSeconds", opt->expire_after_seconds); } if (opt->v != def_opt->v) { BSON_APPEND_INT32 (&doc, "v", opt->v); } if (opt->weights && (opt->weights != def_opt->weights)) { BSON_APPEND_DOCUMENT (&doc, "weights", opt->weights); } if (opt->default_language != def_opt->default_language) { BSON_APPEND_UTF8 (&doc, "default_language", opt->default_language); } if (opt->language_override != def_opt->language_override) { BSON_APPEND_UTF8 (&doc, "language_override", opt->language_override); } if (opt->partial_filter_expression) { BSON_APPEND_DOCUMENT (&doc, "partialFilterExpression", opt->partial_filter_expression); } if (opt->geo_options) { geo_opt = opt->geo_options; def_geo = mongoc_index_opt_geo_get_default (); if (geo_opt->twod_sphere_version != def_geo->twod_sphere_version) { BSON_APPEND_INT32 (&doc, "2dsphereIndexVersion", geo_opt->twod_sphere_version); } if (geo_opt->twod_bits_precision != def_geo->twod_bits_precision) { BSON_APPEND_INT32 (&doc, "bits", geo_opt->twod_bits_precision); } if (geo_opt->twod_location_min != def_geo->twod_location_min) { BSON_APPEND_DOUBLE (&doc, "min", geo_opt->twod_location_min); } if (geo_opt->twod_location_max != def_geo->twod_location_max) { BSON_APPEND_DOUBLE (&doc, "max", geo_opt->twod_location_max); } if (geo_opt->haystack_bucket_size != def_geo->haystack_bucket_size) { BSON_APPEND_DOUBLE (&doc, "bucketSize", geo_opt->haystack_bucket_size); } } if (opt->storage_options) { storage_opt = opt->storage_options; switch (storage_opt->type) { case MONGOC_INDEX_STORAGE_OPT_WIREDTIGER: wt_opt = (mongoc_index_opt_wt_t *)storage_opt; BSON_APPEND_DOCUMENT_BEGIN (&doc, "storageEngine", &storage_doc); BSON_APPEND_DOCUMENT_BEGIN (&storage_doc, "wiredTiger", &wt_doc); BSON_APPEND_UTF8 (&wt_doc, "configString", wt_opt->config_str); bson_append_document_end (&storage_doc, &wt_doc); bson_append_document_end (&doc, &storage_doc); break; default: break; } } bson_append_document_end (&ar, &doc); bson_append_array_end (&cmd, &ar); ret = mongoc_collection_command_simple (collection, &cmd, NULL, &reply, &local_error); /* * If we failed due to the command not being found, then use the legacy * version which performs an insert into the system.indexes collection. */ if (!ret) { if (local_error.code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND) { ret = _mongoc_collection_create_index_legacy (collection, keys, opt, error); } else if (error) { memcpy (error, &local_error, sizeof *error); } } bson_destroy (&cmd); bson_destroy (&reply); bson_free (alloc_name); return ret; } bool mongoc_collection_ensure_index (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, bson_error_t *error) { return mongoc_collection_create_index (collection, keys, opt, error); } mongoc_cursor_t * _mongoc_collection_find_indexes_legacy (mongoc_collection_t *collection, bson_error_t *error) { mongoc_database_t *db; mongoc_collection_t *idx_collection; mongoc_read_prefs_t *read_prefs; bson_t query = BSON_INITIALIZER; mongoc_cursor_t *cursor; BSON_ASSERT (collection); BSON_APPEND_UTF8 (&query, "ns", collection->ns); db = mongoc_client_get_database (collection->client, collection->db); BSON_ASSERT (db); idx_collection = mongoc_database_get_collection (db, "system.indexes"); BSON_ASSERT (idx_collection); read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); cursor = mongoc_collection_find (idx_collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, read_prefs); mongoc_read_prefs_destroy (read_prefs); mongoc_collection_destroy (idx_collection); mongoc_database_destroy (db); return cursor; } mongoc_cursor_t * mongoc_collection_find_indexes (mongoc_collection_t *collection, bson_error_t *error) { mongoc_cursor_t *cursor; bson_t cmd = BSON_INITIALIZER; bson_t child; BSON_ASSERT (collection); bson_append_utf8 (&cmd, "listIndexes", -1, collection->collection, collection->collectionlen); BSON_APPEND_DOCUMENT_BEGIN (&cmd, "cursor", &child); bson_append_document_end (&cmd, &child); cursor = _mongoc_collection_cursor_new (collection, MONGOC_QUERY_SLAVE_OK); _mongoc_cursor_cursorid_init (cursor, &cmd); if (_mongoc_cursor_cursorid_prime (cursor)) { /* intentionally empty */ } else { if (mongoc_cursor_error (cursor, error)) { mongoc_cursor_destroy (cursor); if (error->code == MONGOC_ERROR_COLLECTION_DOES_NOT_EXIST) { bson_t empty_arr = BSON_INITIALIZER; /* collection does not exist. in accordance with the spec we return * an empty array. Also we need to clear out the error. */ error->code = 0; error->domain = 0; cursor = _mongoc_collection_cursor_new (collection, MONGOC_QUERY_SLAVE_OK); _mongoc_cursor_array_init (cursor, NULL, NULL); _mongoc_cursor_array_set_bson (cursor, &empty_arr); } else if (error->code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND) { /* talking to an old server. */ /* clear out error. */ error->code = 0; error->domain = 0; cursor = _mongoc_collection_find_indexes_legacy (collection, error); } } } bson_destroy (&cmd); return cursor; } /* *-------------------------------------------------------------------------- * * mongoc_collection_insert_bulk -- * * Bulk insert documents into a MongoDB collection. * * Parameters: * @collection: A mongoc_collection_t. * @flags: flags for the insert or 0. * @documents: The documents to insert. * @n_documents: The number of documents to insert. * @write_concern: A write concern or NULL. * @error: a location for an error or NULL. * * Returns: * true if successful; otherwise false and @error is set. * * If the write concern does not dictate checking the result of the * insert, then true may be returned even though the document was * not actually inserted on the MongoDB server or cluster. * * Side effects: * @collection->gle is setup, depending on write_concern->w value. * @error may be set upon failure if non-NULL. * *-------------------------------------------------------------------------- */ bool mongoc_collection_insert_bulk (mongoc_collection_t *collection, mongoc_insert_flags_t flags, const bson_t **documents, uint32_t n_documents, const mongoc_write_concern_t *write_concern, bson_error_t *error) { mongoc_write_command_t command; mongoc_write_result_t result; mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; bool ret; uint32_t i; BSON_ASSERT (collection); BSON_ASSERT (documents); if (!write_concern) { write_concern = collection->write_concern; } if (!(flags & MONGOC_INSERT_NO_VALIDATE)) { int vflags = (BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_DOLLAR_KEYS | BSON_VALIDATE_DOT_KEYS); for (i = 0; i < n_documents; i++) { if (!bson_validate (documents[i], (bson_validate_flags_t)vflags, NULL)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "A document was corrupt or contained " "invalid characters . or $"); RETURN (false); } } } bson_clear (&collection->gle); _mongoc_write_result_init (&result); write_flags.ordered = !(flags & MONGOC_INSERT_CONTINUE_ON_ERROR); _mongoc_write_command_init_insert (&command, NULL, write_flags, true); for (i = 0; i < n_documents; i++) { _mongoc_write_command_insert_append (&command, documents[i]); } _mongoc_collection_write_command_execute (&command, collection, write_concern, &result); collection->gle = bson_new (); ret = _mongoc_write_result_complete (&result, collection->gle, error); _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); return ret; } /* *-------------------------------------------------------------------------- * * mongoc_collection_insert -- * * Insert a document into a MongoDB collection. * * Parameters: * @collection: A mongoc_collection_t. * @flags: flags for the insert or 0. * @document: The document to insert. * @write_concern: A write concern or NULL. * @error: a location for an error or NULL. * * Returns: * true if successful; otherwise false and @error is set. * * If the write concern does not dictate checking the result of the * insert, then true may be returned even though the document was * not actually inserted on the MongoDB server or cluster. * * Side effects: * @collection->gle is setup, depending on write_concern->w value. * @error may be set upon failure if non-NULL. * *-------------------------------------------------------------------------- */ bool mongoc_collection_insert (mongoc_collection_t *collection, mongoc_insert_flags_t flags, const bson_t *document, const mongoc_write_concern_t *write_concern, bson_error_t *error) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_command_t command; mongoc_write_result_t result; bool ret; ENTRY; BSON_ASSERT (collection); BSON_ASSERT (document); bson_clear (&collection->gle); if (!write_concern) { write_concern = collection->write_concern; } if (!(flags & MONGOC_INSERT_NO_VALIDATE)) { int vflags = (BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_DOLLAR_KEYS | BSON_VALIDATE_DOT_KEYS); if (!bson_validate (document, (bson_validate_flags_t)vflags, NULL)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "A document was corrupt or contained " "invalid characters . or $"); RETURN (false); } } _mongoc_write_result_init (&result); _mongoc_write_command_init_insert (&command, document, write_flags, false); _mongoc_collection_write_command_execute (&command, collection, write_concern, &result); collection->gle = bson_new (); ret = _mongoc_write_result_complete (&result, collection->gle, error); _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_collection_update -- * * Updates one or more documents matching @selector with @update. * * Parameters: * @collection: A mongoc_collection_t. * @flags: The flags for the update. * @selector: A bson_t containing your selector. * @update: A bson_t containing your update document. * @write_concern: The write concern or NULL. * @error: A location for an error or NULL. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @collection->gle is setup, depending on write_concern->w value. * @error is setup upon failure. * *-------------------------------------------------------------------------- */ bool mongoc_collection_update (mongoc_collection_t *collection, mongoc_update_flags_t uflags, const bson_t *selector, const bson_t *update, const mongoc_write_concern_t *write_concern, bson_error_t *error) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_command_t command; mongoc_write_result_t result; bson_iter_t iter; size_t err_offset; bool ret; int vflags = (BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_DOLLAR_KEYS | BSON_VALIDATE_DOT_KEYS); int flags = uflags; ENTRY; BSON_ASSERT (collection); BSON_ASSERT (selector); BSON_ASSERT (update); bson_clear (&collection->gle); if (!write_concern) { write_concern = collection->write_concern; } if (!((uint32_t)flags & MONGOC_UPDATE_NO_VALIDATE) && bson_iter_init (&iter, update) && bson_iter_next (&iter) && (bson_iter_key (&iter) [0] != '$') && !bson_validate (update, (bson_validate_flags_t)vflags, &err_offset)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "update document is corrupt or contains " "invalid keys including $ or ."); return false; } else { flags = (uint32_t)flags & ~MONGOC_UPDATE_NO_VALIDATE; } _mongoc_write_result_init (&result); _mongoc_write_command_init_update (&command, selector, update, !!(flags & MONGOC_UPDATE_UPSERT), !!(flags & MONGOC_UPDATE_MULTI_UPDATE), write_flags); _mongoc_collection_write_command_execute (&command, collection, write_concern, &result); collection->gle = bson_new (); ret = _mongoc_write_result_complete (&result, collection->gle, error); _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_collection_save -- * * Save @document to @collection. * * If the document has an _id field, it will be updated. Otherwise, * the document will be inserted into the collection. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @error is set upon failure if non-NULL. * *-------------------------------------------------------------------------- */ bool mongoc_collection_save (mongoc_collection_t *collection, const bson_t *document, const mongoc_write_concern_t *write_concern, bson_error_t *error) { bson_iter_t iter; bool ret; bson_t selector; BSON_ASSERT (collection); BSON_ASSERT (document); if (!bson_iter_init_find(&iter, document, "_id")) { return mongoc_collection_insert(collection, MONGOC_INSERT_NONE, document, write_concern, error); } bson_init(&selector); if (!bson_append_iter(&selector, NULL, 0, &iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Failed to append bson to create update."); bson_destroy (&selector); return NULL; } ret = mongoc_collection_update(collection, MONGOC_UPDATE_UPSERT, &selector, document, write_concern, error); bson_destroy(&selector); return ret; } /* *-------------------------------------------------------------------------- * * mongoc_collection_remove -- * * Delete one or more items from a collection. If you want to * limit to a single delete, provided MONGOC_REMOVE_SINGLE_REMOVE * for @flags. * * Parameters: * @collection: A mongoc_collection_t. * @flags: the delete flags or 0. * @selector: A selector of documents to delete. * @write_concern: A write concern or NULL. If NULL, the default * write concern for the collection will be used. * @error: A location for an error or NULL. * * Returns: * true if successful; otherwise false and error is set. * * If the write concern does not dictate checking the result, this * function may return true even if it failed. * * Side effects: * @collection->gle is setup, depending on write_concern->w value. * @error is setup upon failure. * *-------------------------------------------------------------------------- */ bool mongoc_collection_remove (mongoc_collection_t *collection, mongoc_remove_flags_t flags, const bson_t *selector, const mongoc_write_concern_t *write_concern, bson_error_t *error) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_command_t command; mongoc_write_result_t result; bool multi; bool ret; ENTRY; BSON_ASSERT (collection); BSON_ASSERT (selector); bson_clear (&collection->gle); if (!write_concern) { write_concern = collection->write_concern; } multi = !(flags & MONGOC_REMOVE_SINGLE_REMOVE); _mongoc_write_result_init (&result); _mongoc_write_command_init_delete (&command, selector, multi, write_flags); _mongoc_collection_write_command_execute (&command, collection, write_concern, &result); collection->gle = bson_new (); ret = _mongoc_write_result_complete (&result, collection->gle, error); _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); RETURN (ret); } bool mongoc_collection_delete (mongoc_collection_t *collection, mongoc_delete_flags_t flags, const bson_t *selector, const mongoc_write_concern_t *write_concern, bson_error_t *error) { return mongoc_collection_remove (collection, (mongoc_remove_flags_t)flags, selector, write_concern, error); } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_read_prefs -- * * Fetch the default read preferences for the collection. * * Returns: * A mongoc_read_prefs_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_prefs_t * mongoc_collection_get_read_prefs (const mongoc_collection_t *collection) { BSON_ASSERT (collection); return collection->read_prefs; } /* *-------------------------------------------------------------------------- * * mongoc_collection_set_read_prefs -- * * Sets the default read preferences for the collection instance. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_collection_set_read_prefs (mongoc_collection_t *collection, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (collection); if (collection->read_prefs) { mongoc_read_prefs_destroy(collection->read_prefs); collection->read_prefs = NULL; } if (read_prefs) { collection->read_prefs = mongoc_read_prefs_copy(read_prefs); } } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_read_concern -- * * Fetches the default read concern for the collection instance. * * Returns: * A mongoc_read_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_concern_t * mongoc_collection_get_read_concern (const mongoc_collection_t *collection) { BSON_ASSERT (collection); return collection->read_concern; } /* *-------------------------------------------------------------------------- * * mongoc_collection_set_read_concern -- * * Sets the default read concern for the collection instance. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_collection_set_read_concern (mongoc_collection_t *collection, const mongoc_read_concern_t *read_concern) { BSON_ASSERT (collection); if (collection->read_concern) { mongoc_read_concern_destroy (collection->read_concern); collection->read_concern = NULL; } if (read_concern) { collection->read_concern = mongoc_read_concern_copy (read_concern); } } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_write_concern -- * * Fetches the default write concern for the collection instance. * * Returns: * A mongoc_write_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_write_concern_t * mongoc_collection_get_write_concern (const mongoc_collection_t *collection) { BSON_ASSERT (collection); return collection->write_concern; } /* *-------------------------------------------------------------------------- * * mongoc_collection_set_write_concern -- * * Sets the default write concern for the collection instance. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_collection_set_write_concern (mongoc_collection_t *collection, const mongoc_write_concern_t *write_concern) { BSON_ASSERT (collection); if (collection->write_concern) { mongoc_write_concern_destroy(collection->write_concern); collection->write_concern = NULL; } if (write_concern) { collection->write_concern = mongoc_write_concern_copy(write_concern); } } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_name -- * * Returns the name of the collection, excluding the database name. * * Returns: * A string which should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const char * mongoc_collection_get_name (mongoc_collection_t *collection) { BSON_ASSERT (collection); return collection->collection; } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_last_error -- * * Returns getLastError document, according to write_concern on last * executed command for current collection instance. * * Returns: * NULL or a bson_t that should not be modified or freed. This value * is not guaranteed to be persistent between calls into the * mongoc_collection_t instance, and therefore must be copied if * you would like to keep it around. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const bson_t * mongoc_collection_get_last_error (const mongoc_collection_t *collection) /* IN */ { BSON_ASSERT (collection); return collection->gle; } /* *-------------------------------------------------------------------------- * * mongoc_collection_validate -- * * Helper to call the validate command on the MongoDB server to * validate the collection. * * Options may be additional options, or NULL. * Currently supported options are: * * "full": Boolean * * If full is true, then perform a more resource intensive * validation. * * The result is stored in reply. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @reply is set if successful. * @error may be set. * *-------------------------------------------------------------------------- */ bool mongoc_collection_validate (mongoc_collection_t *collection, /* IN */ const bson_t *options, /* IN */ bson_t *reply, /* OUT */ bson_error_t *error) /* IN */ { bson_iter_t iter; bson_t cmd = BSON_INITIALIZER; bool ret; BSON_ASSERT (collection); if (options && bson_iter_init_find (&iter, options, "full") && !BSON_ITER_HOLDS_BOOL (&iter)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "'full' must be a boolean value."); return false; } bson_append_utf8 (&cmd, "validate", 8, collection->collection, collection->collectionlen); if (options) { bson_concat (&cmd, options); } ret = mongoc_collection_command_simple (collection, &cmd, NULL, reply, error); bson_destroy (&cmd); return ret; } /* *-------------------------------------------------------------------------- * * mongoc_collection_rename -- * * Rename the collection to @new_name. * * If @new_db is NULL, the same db will be used. * * If @drop_target_before_rename is true, then a collection named * @new_name will be dropped before renaming @collection to * @new_name. * * Returns: * true on success; false on failure and @error is set. * * Side effects: * @error is set on failure. * *-------------------------------------------------------------------------- */ bool mongoc_collection_rename (mongoc_collection_t *collection, const char *new_db, const char *new_name, bool drop_target_before_rename, bson_error_t *error) { bson_t cmd = BSON_INITIALIZER; char newns [MONGOC_NAMESPACE_MAX + 1]; bool ret; BSON_ASSERT (collection); BSON_ASSERT (new_name); if (!validate_name (new_name)) { bson_set_error (error, MONGOC_ERROR_NAMESPACE, MONGOC_ERROR_NAMESPACE_INVALID, "\"%s\" is an invalid collection name.", new_name); return false; } bson_snprintf (newns, sizeof newns, "%s.%s", new_db ? new_db : collection->db, new_name); BSON_APPEND_UTF8 (&cmd, "renameCollection", collection->ns); BSON_APPEND_UTF8 (&cmd, "to", newns); if (drop_target_before_rename) { BSON_APPEND_BOOL (&cmd, "dropTarget", true); } ret = mongoc_client_command_simple (collection->client, "admin", &cmd, NULL, NULL, error); if (ret) { if (new_db) { bson_snprintf (collection->db, sizeof collection->db, "%s", new_db); } bson_snprintf (collection->collection, sizeof collection->collection, "%s", new_name); collection->collectionlen = (int) strlen (collection->collection); bson_snprintf (collection->ns, sizeof collection->ns, "%s.%s", collection->db, new_name); collection->nslen = (int) strlen (collection->ns); } bson_destroy (&cmd); return ret; } /* *-------------------------------------------------------------------------- * * mongoc_collection_stats -- * * Fetches statistics about the collection. * * The result is stored in @stats, which should NOT be an initialized * bson_t or a leak will occur. * * @stats, @options, and @error are optional. * * Returns: * true on success and @stats is set. * false on failure and @error is set. * * Side effects: * @stats and @error. * *-------------------------------------------------------------------------- */ bool mongoc_collection_stats (mongoc_collection_t *collection, const bson_t *options, bson_t *stats, bson_error_t *error) { bson_iter_t iter; bson_t cmd = BSON_INITIALIZER; bool ret; BSON_ASSERT (collection); if (options && bson_iter_init_find (&iter, options, "scale") && !BSON_ITER_HOLDS_INT32 (&iter)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "'scale' must be an int32 value."); return false; } BSON_APPEND_UTF8 (&cmd, "collStats", collection->collection); if (options) { bson_concat (&cmd, options); } ret = mongoc_collection_command_simple (collection, &cmd, NULL, stats, error); bson_destroy (&cmd); return ret; } mongoc_bulk_operation_t * mongoc_collection_create_bulk_operation ( mongoc_collection_t *collection, bool ordered, const mongoc_write_concern_t *write_concern) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; BSON_ASSERT (collection); if (!write_concern) { write_concern = collection->write_concern; } write_flags.ordered = ordered; return _mongoc_bulk_operation_new (collection->client, collection->db, collection->collection, write_flags, write_concern); } /* *-------------------------------------------------------------------------- * * mongoc_collection_find_and_modify_with_opts -- * * Find a document in @collection matching @query, applying @opts. * * If @reply is not NULL, then the result document will be placed * in reply and should be released with bson_destroy(). * * See http://docs.mongodb.org/manual/reference/command/findAndModify/ * for more information. * * Returns: * true on success; false on failure. * * Side effects: * reply is initialized. * error is set if false is returned. * *-------------------------------------------------------------------------- */ bool mongoc_collection_find_and_modify_with_opts (mongoc_collection_t *collection, const bson_t *query, const mongoc_find_and_modify_opts_t *opts, bson_t *reply, bson_error_t *error) { mongoc_cluster_t *cluster; mongoc_server_stream_t *server_stream; bson_iter_t iter; bson_iter_t inner; const char *name; bson_t reply_local; bool ret; bson_t command = BSON_INITIALIZER; ENTRY; BSON_ASSERT (collection); BSON_ASSERT (query); cluster = &collection->client->cluster; server_stream = mongoc_cluster_stream_for_writes (cluster, error); if (!server_stream) { bson_destroy (&command); RETURN (false); } name = mongoc_collection_get_name (collection); BSON_APPEND_UTF8 (&command, "findAndModify", name); BSON_APPEND_DOCUMENT (&command, "query", query); if (opts->sort) { BSON_APPEND_DOCUMENT (&command, "sort", opts->sort); } if (opts->update) { BSON_APPEND_DOCUMENT (&command, "update", opts->update); } if (opts->fields) { BSON_APPEND_DOCUMENT (&command, "fields", opts->fields); } if (opts->flags & MONGOC_FIND_AND_MODIFY_REMOVE) { BSON_APPEND_BOOL (&command, "remove", true); } if (opts->flags & MONGOC_FIND_AND_MODIFY_UPSERT) { BSON_APPEND_BOOL (&command, "upsert", true); } if (opts->flags & MONGOC_FIND_AND_MODIFY_RETURN_NEW) { BSON_APPEND_BOOL (&command, "new", true); } if (opts->bypass_document_validation != MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT) { BSON_APPEND_BOOL (&command, "bypassDocumentValidation", !!opts->bypass_document_validation); } if (server_stream->sd->max_wire_version >= WIRE_VERSION_FAM_WRITE_CONCERN) { if (!_mongoc_write_concern_is_valid (collection->write_concern)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The write concern is invalid."); bson_destroy (&command); mongoc_server_stream_cleanup (server_stream); RETURN (false); } if (_mongoc_write_concern_needs_gle (collection->write_concern)) { _BSON_APPEND_WRITE_CONCERN (&command, collection->write_concern); } } ret = mongoc_cluster_run_command (cluster, server_stream->stream, MONGOC_QUERY_NONE, collection->db, &command, &reply_local, error); if (bson_iter_init_find (&iter, &reply_local, "writeConcernError") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { const char *errmsg = NULL; int32_t code = 0; bson_iter_recurse(&iter, &inner); while (bson_iter_next (&inner)) { if (BSON_ITER_IS_KEY (&inner, "code")) { code = bson_iter_int32 (&inner); } else if (BSON_ITER_IS_KEY (&inner, "errmsg")) { errmsg = bson_iter_utf8 (&inner, NULL); } } bson_set_error (error, MONGOC_ERROR_WRITE_CONCERN, code, "Write Concern error: %s", errmsg); } if (reply) { bson_copy_to (&reply_local, reply); } bson_destroy (&reply_local); bson_destroy (&command); mongoc_server_stream_cleanup (server_stream); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_collection_find_and_modify -- * * Find a document in @collection matching @query and update it with * the update document @update. * * If @reply is not NULL, then the result document will be placed * in reply and should be released with bson_destroy(). * * If @remove is true, then the matching documents will be removed. * * If @fields is not NULL, it will be used to select the desired * resulting fields. * * If @_new is true, then the new version of the document is returned * instead of the old document. * * See http://docs.mongodb.org/manual/reference/command/findAndModify/ * for more information. * * Returns: * true on success; false on failure. * * Side effects: * reply is initialized. * error is set if false is returned. * *-------------------------------------------------------------------------- */ bool mongoc_collection_find_and_modify (mongoc_collection_t *collection, const bson_t *query, const bson_t *sort, const bson_t *update, const bson_t *fields, bool _remove, bool upsert, bool _new, bson_t *reply, bson_error_t *error) { mongoc_find_and_modify_opts_t *opts; int flags = 0; bool ret; ENTRY; BSON_ASSERT (collection); BSON_ASSERT (query); BSON_ASSERT (update || _remove); if (_remove) { flags |= MONGOC_FIND_AND_MODIFY_REMOVE; } if (upsert) { flags |= MONGOC_FIND_AND_MODIFY_UPSERT; } if (_new) { flags |= MONGOC_FIND_AND_MODIFY_RETURN_NEW; } opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_sort (opts, sort); mongoc_find_and_modify_opts_set_update (opts, update); mongoc_find_and_modify_opts_set_fields (opts, fields); mongoc_find_and_modify_opts_set_flags (opts, flags); ret = mongoc_collection_find_and_modify_with_opts (collection, query, opts, reply, error); mongoc_find_and_modify_opts_destroy (opts); return ret; } libmongoc-1.3.1/src/mongoc/mongoc-collection.h000066400000000000000000000374371264720626300213500ustar00rootroot00000000000000/* * Copyright 2013-2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_COLLECTION_H #define MONGOC_COLLECTION_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-bulk-operation.h" #include "mongoc-flags.h" #include "mongoc-cursor.h" #include "mongoc-index.h" #include "mongoc-read-prefs.h" #include "mongoc-read-concern.h" #include "mongoc-write-concern.h" #include "mongoc-find-and-modify.h" BSON_BEGIN_DECLS typedef struct _mongoc_collection_t mongoc_collection_t; mongoc_cursor_t *mongoc_collection_aggregate (mongoc_collection_t *collection, mongoc_query_flags_t flags, const bson_t *pipeline, const bson_t *options, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT; void mongoc_collection_destroy (mongoc_collection_t *collection); mongoc_collection_t *mongoc_collection_copy (mongoc_collection_t *collection); mongoc_cursor_t *mongoc_collection_command (mongoc_collection_t *collection, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *command, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT; bool mongoc_collection_command_simple (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error); int64_t mongoc_collection_count (mongoc_collection_t *collection, mongoc_query_flags_t flags, const bson_t *query, int64_t skip, int64_t limit, const mongoc_read_prefs_t *read_prefs, bson_error_t *error); int64_t mongoc_collection_count_with_opts (mongoc_collection_t *collection, mongoc_query_flags_t flags, const bson_t *query, int64_t skip, int64_t limit, const bson_t *opts, const mongoc_read_prefs_t *read_prefs, bson_error_t *error); bool mongoc_collection_drop (mongoc_collection_t *collection, bson_error_t *error); bool mongoc_collection_drop_index (mongoc_collection_t *collection, const char *index_name, bson_error_t *error); bool mongoc_collection_create_index (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, bson_error_t *error); bool mongoc_collection_ensure_index (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, bson_error_t *error) BSON_GNUC_DEPRECATED_FOR (mongoc_collection_create_index); mongoc_cursor_t *mongoc_collection_find_indexes (mongoc_collection_t *collection, bson_error_t *error); mongoc_cursor_t *mongoc_collection_find (mongoc_collection_t *collection, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT; bool mongoc_collection_insert (mongoc_collection_t *collection, mongoc_insert_flags_t flags, const bson_t *document, const mongoc_write_concern_t *write_concern, bson_error_t *error); bool mongoc_collection_insert_bulk (mongoc_collection_t *collection, mongoc_insert_flags_t flags, const bson_t **documents, uint32_t n_documents, const mongoc_write_concern_t *write_concern, bson_error_t *error) BSON_GNUC_DEPRECATED_FOR (mongoc_collection_create_bulk_operation); bool mongoc_collection_update (mongoc_collection_t *collection, mongoc_update_flags_t flags, const bson_t *selector, const bson_t *update, const mongoc_write_concern_t *write_concern, bson_error_t *error); bool mongoc_collection_delete (mongoc_collection_t *collection, mongoc_delete_flags_t flags, const bson_t *selector, const mongoc_write_concern_t *write_concern, bson_error_t *error) BSON_GNUC_DEPRECATED_FOR (mongoc_collection_remove); bool mongoc_collection_save (mongoc_collection_t *collection, const bson_t *document, const mongoc_write_concern_t *write_concern, bson_error_t *error); bool mongoc_collection_remove (mongoc_collection_t *collection, mongoc_remove_flags_t flags, const bson_t *selector, const mongoc_write_concern_t *write_concern, bson_error_t *error); bool mongoc_collection_rename (mongoc_collection_t *collection, const char *new_db, const char *new_name, bool drop_target_before_rename, bson_error_t *error); bool mongoc_collection_find_and_modify_with_opts (mongoc_collection_t *collection, const bson_t *query, const mongoc_find_and_modify_opts_t *opts, bson_t *reply, bson_error_t *error); bool mongoc_collection_find_and_modify (mongoc_collection_t *collection, const bson_t *query, const bson_t *sort, const bson_t *update, const bson_t *fields, bool _remove, bool upsert, bool _new, bson_t *reply, bson_error_t *error); bool mongoc_collection_stats (mongoc_collection_t *collection, const bson_t *options, bson_t *reply, bson_error_t *error); mongoc_bulk_operation_t *mongoc_collection_create_bulk_operation(mongoc_collection_t *collection, bool ordered, const mongoc_write_concern_t *write_concern) BSON_GNUC_WARN_UNUSED_RESULT; const mongoc_read_prefs_t *mongoc_collection_get_read_prefs (const mongoc_collection_t *collection); void mongoc_collection_set_read_prefs (mongoc_collection_t *collection, const mongoc_read_prefs_t *read_prefs); const mongoc_read_concern_t *mongoc_collection_get_read_concern (const mongoc_collection_t *collection); void mongoc_collection_set_read_concern (mongoc_collection_t *collection, const mongoc_read_concern_t *read_concern); const mongoc_write_concern_t *mongoc_collection_get_write_concern (const mongoc_collection_t *collection); void mongoc_collection_set_write_concern (mongoc_collection_t *collection, const mongoc_write_concern_t *write_concern); const char *mongoc_collection_get_name (mongoc_collection_t *collection); const bson_t *mongoc_collection_get_last_error (const mongoc_collection_t *collection); char *mongoc_collection_keys_to_index_string (const bson_t *keys); bool mongoc_collection_validate (mongoc_collection_t *collection, const bson_t *options, bson_t *reply, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_COLLECTION_H */ libmongoc-1.3.1/src/mongoc/mongoc-config.h.in000066400000000000000000000034741264720626300210610ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CONFIG_H #define MONGOC_CONFIG_H /* * MONGOC_ENABLE_SSL is set from configure to determine if we are * compiled with SSL support. */ #define MONGOC_ENABLE_SSL @MONGOC_ENABLE_SSL@ #if MONGOC_ENABLE_SSL != 1 # undef MONGOC_ENABLE_SSL #endif /* * MONGOC_ENABLE_SASL is set from configure to determine if we are * compiled with SASL support. */ #define MONGOC_ENABLE_SASL @MONGOC_ENABLE_SASL@ #if MONGOC_ENABLE_SASL != 1 # undef MONGOC_ENABLE_SASL #endif /* * MONGOC_HAVE_SASL_CLIENT_DONE is set from configure to determine if we * have SASL and its version is new enough to use sasl_client_done (), * which supersedes sasl_done (). */ #define MONGOC_HAVE_SASL_CLIENT_DONE @MONGOC_HAVE_SASL_CLIENT_DONE@ #if MONGOC_HAVE_SASL_CLIENT_DONE != 1 # undef MONGOC_HAVE_SASL_CLIENT_DONE #endif /* * MONGOC_HAVE_WEAK_SYMBOLS is set from configure to determine if the * compiler supports the (weak) annotation. We use it to prevent * Link-Time-Optimization (LTO) in our constant-time mongoc_memcmp() * This is known to work with GNU GCC and Solaris Studio */ #define MONGOC_HAVE_WEAK_SYMBOLS @MONGOC_HAVE_WEAK_SYMBOLS@ #if MONGOC_HAVE_WEAK_SYMBOLS != 1 # undef MONGOC_HAVE_WEAK_SYMBOLS #endif #endif /* MONGOC_CONFIG_H */ libmongoc-1.3.1/src/mongoc/mongoc-counters-private.h000066400000000000000000000073561264720626300225240ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_COUNTERS_PRIVATE_H #define MONGOC_COUNTERS_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #ifdef __linux__ # include # include #elif defined(__FreeBSD__) || \ defined(__NetBSD__) || \ defined(__DragonFly__) || \ defined(__OpenBSD__) # include # include # include #endif BSON_BEGIN_DECLS void _mongoc_counters_init (void); void _mongoc_counters_cleanup (void); static BSON_INLINE unsigned _mongoc_get_cpu_count (void) { #if defined(__linux__) return get_nprocs (); #elif defined(__FreeBSD__) || \ defined(__NetBSD__) || \ defined(__DragonFly__) || \ defined(__OpenBSD__) int mib[2]; int maxproc; size_t len; mib[0] = CTL_HW; mib[1] = HW_NCPU; len = sizeof (maxproc); if (-1 == sysctl (mib, 2, &maxproc, &len, NULL, 0)) { return 1; } return len; #elif defined(__APPLE__) || defined(__sun) int ncpu; ncpu = (int) sysconf (_SC_NPROCESSORS_ONLN); return (ncpu > 0) ? ncpu : 1; #elif defined(_MSC_VER) || defined(_WIN32) SYSTEM_INFO si; GetSystemInfo (&si); return si.dwNumberOfProcessors; #else # warning "_mongoc_get_cpu_count() not supported, defaulting to 1." return 1; #endif } #define _mongoc_counter_add(v,count) \ bson_atomic_int64_add(&(v), (count)) #if defined(ENABLE_RDTSCP) static BSON_INLINE unsigned _mongoc_sched_getcpu (void) { volatile uint32_t rax, rdx, aux; __asm__ volatile ("rdtscp\n" : "=a" (rax), "=d" (rdx), "=c" (aux) : : ); return aux; } #elif defined(HAVE_SCHED_GETCPU) # define _mongoc_sched_getcpu sched_getcpu #else # define _mongoc_sched_getcpu() (0) #endif #ifndef SLOTS_PER_CACHELINE # define SLOTS_PER_CACHELINE 8 #endif typedef struct { int64_t slots [SLOTS_PER_CACHELINE]; } mongoc_counter_slots_t; typedef struct { mongoc_counter_slots_t *cpus; } mongoc_counter_t; #define COUNTER(ident, Category, Name, Description) \ extern mongoc_counter_t __mongoc_counter_##ident; #include "mongoc-counters.defs" #undef COUNTER enum { #define COUNTER(ident, Category, Name, Description) \ COUNTER_##ident, #include "mongoc-counters.defs" #undef COUNTER LAST_COUNTER }; #define COUNTER(ident, Category, Name, Description) \ static BSON_INLINE void \ mongoc_counter_##ident##_add (int64_t val) \ { \ _mongoc_counter_add(\ __mongoc_counter_##ident.cpus[_mongoc_sched_getcpu()].slots[ \ COUNTER_##ident%SLOTS_PER_CACHELINE], val); \ } \ static BSON_INLINE void \ mongoc_counter_##ident##_inc (void) \ { \ mongoc_counter_##ident##_add (1); \ } \ static BSON_INLINE void \ mongoc_counter_##ident##_dec (void) \ { \ mongoc_counter_##ident##_add (-1); \ } \ static BSON_INLINE void \ mongoc_counter_##ident##_reset (void) \ { \ uint32_t i; \ for (i = 0; i < _mongoc_get_cpu_count(); i++) { \ __mongoc_counter_##ident.cpus [i].slots [\ COUNTER_##ident%SLOTS_PER_CACHELINE] = 0; \ } \ bson_memory_barrier (); \ } #include "mongoc-counters.defs" #undef COUNTER BSON_END_DECLS #endif /* MONGOC_COUNTERS_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-counters.c000066400000000000000000000165401264720626300210420ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #ifdef BSON_OS_UNIX #include #include #endif #ifdef _MSC_VER # include #endif #include "mongoc-counters-private.h" #include "mongoc-log.h" #pragma pack(1) typedef struct { uint32_t offset; uint32_t slot; char category[24]; char name[32]; char description[64]; } mongoc_counter_info_t; #pragma pack() BSON_STATIC_ASSERT(sizeof(mongoc_counter_info_t) == 128); #pragma pack(1) typedef struct { uint32_t size; uint32_t n_cpu; uint32_t n_counters; uint32_t infos_offset; uint32_t values_offset; uint8_t padding[44]; } mongoc_counters_t; #pragma pack() BSON_STATIC_ASSERT(sizeof(mongoc_counters_t) == 64); static void *gCounterFallback = NULL; #define COUNTER(ident, Category, Name, Description) \ mongoc_counter_t __mongoc_counter_##ident; #include "mongoc-counters.defs" #undef COUNTER /** * mongoc_counters_use_shm: * * Checks to see if counters should be exported over a shared memory segment. * * Returns: true if SHM is to be used. */ #if defined(BSON_OS_UNIX) && defined(MONGOC_ENABLE_SHM_COUNTERS) static bool mongoc_counters_use_shm (void) { return !getenv("MONGOC_DISABLE_SHM"); } #endif /** * mongoc_counters_calc_size: * * Returns the number of bytes required for the shared memory segment of * the process. This segment contains the various statistical counters for * the process. * * Returns: The number of bytes required. */ static size_t mongoc_counters_calc_size (void) { size_t n_cpu; size_t n_groups; size_t size; n_cpu = _mongoc_get_cpu_count(); n_groups = (LAST_COUNTER / SLOTS_PER_CACHELINE) + 1; size = (sizeof(mongoc_counters_t) + (LAST_COUNTER * sizeof(mongoc_counter_info_t)) + (n_cpu * n_groups * sizeof(mongoc_counter_slots_t))); #ifdef BSON_OS_UNIX return BSON_MAX(getpagesize(), size); #else return size; #endif } /** * mongoc_counters_destroy: * * Removes the shared memory segment for the current processes counters. */ void _mongoc_counters_cleanup (void) { if (gCounterFallback) { bson_free (gCounterFallback); gCounterFallback = NULL; #if defined(BSON_OS_UNIX) && defined(MONGOC_ENABLE_SHM_COUNTERS) } else { char name [32]; int pid; pid = getpid (); bson_snprintf (name, sizeof name, "/mongoc-%u", pid); shm_unlink (name); #endif } } /** * mongoc_counters_alloc: * @size: The size of the shared memory segment. * * This function allocates the shared memory segment for use by counters * within the process. * * Returns: A shared memory segment, or malloc'd memory on failure. */ static void * mongoc_counters_alloc (size_t size) { #if defined(BSON_OS_UNIX) && defined(MONGOC_ENABLE_SHM_COUNTERS) void *mem; char name[32]; int pid; int fd; if (!mongoc_counters_use_shm ()) { goto use_malloc; } pid = getpid (); bson_snprintf (name, sizeof name, "/mongoc-%u", pid); if (-1 == (fd = shm_open (name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR))) { goto use_malloc; } /* * NOTE: * * ftruncate() will cause reads to be zero. Therefore, we don't need to * do write() of zeroes to initialize the shared memory area. */ if (-1 == ftruncate (fd, size)) { goto failure; } mem = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) { goto failure; } close (fd); memset (mem, 0, size); return mem; failure: shm_unlink (name); close (fd); use_malloc: MONGOC_WARNING("Falling back to malloc for counters."); #endif gCounterFallback = (void *)bson_malloc0 (size); return gCounterFallback; } /** * mongoc_counters_register: * @counters: A mongoc_counter_t. * @num: The counter number. * @category: The counter category. * @name: THe counter name. * @description The counter description. * * Registers a new counter in the memory segment for counters. If the counters * are exported over shared memory, it will be made available. * * Returns: The offset to the data for the counters values. */ static size_t mongoc_counters_register (mongoc_counters_t *counters, uint32_t num, const char *category, const char *name, const char *description) { mongoc_counter_info_t *infos; char *segment; int n_cpu; BSON_ASSERT(counters); BSON_ASSERT(category); BSON_ASSERT(name); BSON_ASSERT(description); /* * Implementation Note: * * The memory barrier is required so that all of the above has been * completed. Then increment the n_counters so that a reading application * only knows about the counter after we have initialized it. */ n_cpu = _mongoc_get_cpu_count(); segment = (char *)counters; infos = (mongoc_counter_info_t *)(segment + counters->infos_offset); infos = &infos[counters->n_counters]; infos->slot = num % SLOTS_PER_CACHELINE; infos->offset = (counters->values_offset + ((num / SLOTS_PER_CACHELINE) * n_cpu * sizeof(mongoc_counter_slots_t))); bson_strncpy (infos->category, category, sizeof infos->category); bson_strncpy (infos->name, name, sizeof infos->name); bson_strncpy (infos->description, description, sizeof infos->description); bson_memory_barrier (); counters->n_counters++; return infos->offset; } /** * mongoc_counters_init: * * Initializes the mongoc counters system. This should be run on library * initialization using the GCC constructor attribute. */ void _mongoc_counters_init (void) { mongoc_counter_info_t *info; mongoc_counters_t *counters; size_t infos_size; size_t off; size_t size; char *segment; size = mongoc_counters_calc_size(); segment = (char *)mongoc_counters_alloc(size); infos_size = LAST_COUNTER * sizeof *info; counters = (mongoc_counters_t *)segment; counters->n_cpu = _mongoc_get_cpu_count(); counters->n_counters = 0; counters->infos_offset = sizeof *counters; counters->values_offset = (uint32_t)(counters->infos_offset + infos_size); BSON_ASSERT ((counters->values_offset % 64) == 0); #define COUNTER(ident, Category, Name, Desc) \ off = mongoc_counters_register(counters, COUNTER_##ident, Category, Name, Desc); \ __mongoc_counter_##ident.cpus = (mongoc_counter_slots_t *)(segment + off); #include "mongoc-counters.defs" #undef COUNTER /* * NOTE: * * Only update the size of the shared memory area for the client after * we have initialized the rest of the counters. Don't forget our memory * barrier to prevent compiler reordering. */ bson_memory_barrier (); counters->size = (uint32_t)size; } libmongoc-1.3.1/src/mongoc/mongoc-counters.defs000066400000000000000000000104501264720626300215330ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ COUNTER(op_egress_total, "Operations", "Egress Total", "The number of sent operations.") COUNTER(op_ingress_total, "Operations", "Ingress Total", "The number of received operations.") COUNTER(op_egress_query, "Operations", "Egress Queries", "The number of sent Query operations.") COUNTER(op_ingress_query, "Operations", "Ingress Queries", "The number of received Query operations.") COUNTER(op_egress_getmore, "Operations", "Egress GetMore", "The number of sent GetMore operations.") COUNTER(op_ingress_getmore, "Operations", "Ingress GetMore", "The number of received GetMore operations.") COUNTER(op_egress_insert, "Operations", "Egress Insert", "The number of sent Insert operations.") COUNTER(op_ingress_insert, "Operations", "Ingress Insert", "The number of received Insert operations.") COUNTER(op_egress_delete, "Operations", "Egress Delete", "The number of sent Delete operations.") COUNTER(op_ingress_delete, "Operations", "Ingress Delete", "The number of received Delete operations.") COUNTER(op_egress_update, "Operations", "Egress Update", "The number of sent Update operations.") COUNTER(op_ingress_update, "Operations", "Ingress Update", "The number of received Update operations.") COUNTER(op_egress_killcursors, "Operations", "Egress KillCursors", "The number of sent KillCursors operations.") COUNTER(op_ingress_killcursors, "Operations", "Ingress KillCursors", "The number of received KillCursors operations.") COUNTER(op_egress_msg, "Operations", "Egress Msg", "The number of sent Msg operations.") COUNTER(op_ingress_msg, "Operations", "Ingress Msg", "The number of received Msg operations.") COUNTER(op_egress_reply, "Operations", "Egress Reply", "The number of sent Reply operations.") COUNTER(op_ingress_reply, "Operations", "Ingress Reply", "The number of received Reply operations.") COUNTER(cursors_active, "Cursors", "Active", "The number of active cursors.") COUNTER(cursors_disposed, "Cursors", "Disposed", "The number of disposed cursors.") COUNTER(clients_active, "Clients", "Active", "The number of active clients.") COUNTER(clients_disposed, "Clients", "Disposed", "The number of disposed clients.") COUNTER(streams_active, "Streams", "Active", "The number of active streams.") COUNTER(streams_disposed, "Streams", "Disposed", "The number of disposed streams.") COUNTER(streams_egress, "Streams", "Egress Bytes", "The number of bytes sent.") COUNTER(streams_ingress, "Streams", "Ingress Bytes", "The number of bytes received.") COUNTER(streams_timeout, "Streams", "N Socket Timeouts", "The number of socket timeouts.") COUNTER(client_pools_active, "Client Pools", "Active", "The number of active client pools.") COUNTER(client_pools_disposed, "Client Pools", "Disposed", "The number of disposed client pools.") COUNTER(protocol_ingress_error, "Protocol", "Ingress Errors", "The number of protocol errors on ingress.") COUNTER(auth_failure, "Auth", "Failures", "The number of failed authentication requests.") COUNTER(auth_success, "Auth", "Success", "The number of successful authentication requests.") COUNTER(dns_failure, "DNS", "Failure", "The number of failed DNS requests.") COUNTER(dns_success, "DNS", "Success", "The number of successful DNS requests.") libmongoc-1.3.1/src/mongoc/mongoc-cursor-array-private.h000066400000000000000000000024031264720626300232770ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CURSOR_ARRAY_PRIVATE_H #define MONGOC_CURSOR_ARRAY_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-cursor-private.h" BSON_BEGIN_DECLS void _mongoc_cursor_array_init (mongoc_cursor_t *cursor, const bson_t *command, const char *field_name); bool _mongoc_cursor_array_prime (mongoc_cursor_t *cursor); void _mongoc_cursor_array_set_bson (mongoc_cursor_t *cursor, const bson_t *bson); BSON_END_DECLS #endif /* MONGOC_CURSOR_ARRAY_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-cursor-array.c000066400000000000000000000116521264720626300216300ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-cursor.h" #include "mongoc-cursor-array-private.h" #include "mongoc-cursor-private.h" #include "mongoc-client-private.h" #include "mongoc-counters-private.h" #include "mongoc-error.h" #include "mongoc-log.h" #include "mongoc-opcode.h" #include "mongoc-trace.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "cursor-array" typedef struct { const bson_t *result; bool has_array; bool has_synthetic_bson; bson_iter_t iter; bson_t bson; uint32_t document_len; const uint8_t *document; const char *field_name; } mongoc_cursor_array_t; static void * _mongoc_cursor_array_new (const char *field_name) { mongoc_cursor_array_t *arr; ENTRY; arr = (mongoc_cursor_array_t *)bson_malloc0 (sizeof *arr); arr->field_name = field_name; RETURN (arr); } static void _mongoc_cursor_array_destroy (mongoc_cursor_t *cursor) { mongoc_cursor_array_t *arr; ENTRY; arr = (mongoc_cursor_array_t *)cursor->iface_data; if (arr->has_synthetic_bson) { bson_destroy(&arr->bson); } bson_free (cursor->iface_data); _mongoc_cursor_destroy (cursor); EXIT; } bool _mongoc_cursor_array_prime (mongoc_cursor_t *cursor) { const bson_t *bson; mongoc_cursor_array_t *arr; bson_iter_t iter; ENTRY; arr = (mongoc_cursor_array_t *)cursor->iface_data; BSON_ASSERT (arr); if (_mongoc_cursor_run_command (cursor, &cursor->query) && _mongoc_read_from_buffer (cursor, &bson) && bson_iter_init_find (&iter, bson, arr->field_name) && BSON_ITER_HOLDS_ARRAY (&iter) && bson_iter_recurse (&iter, &arr->iter)) { arr->has_array = true; } return arr->has_array; } static bool _mongoc_cursor_array_next (mongoc_cursor_t *cursor, const bson_t **bson) { bool ret = true; mongoc_cursor_array_t *arr; ENTRY; arr = (mongoc_cursor_array_t *)cursor->iface_data; *bson = NULL; if (!arr->has_array) { ret = _mongoc_cursor_array_prime(cursor); } if (ret) { ret = bson_iter_next (&arr->iter); } if (ret) { bson_iter_document (&arr->iter, &arr->document_len, &arr->document); bson_init_static (&arr->bson, arr->document, arr->document_len); *bson = &arr->bson; } RETURN (ret); } static mongoc_cursor_t * _mongoc_cursor_array_clone (const mongoc_cursor_t *cursor) { mongoc_cursor_array_t *arr; mongoc_cursor_t *clone_; ENTRY; arr = (mongoc_cursor_array_t *)cursor->iface_data; clone_ = _mongoc_cursor_clone (cursor); _mongoc_cursor_array_init (clone_, &cursor->query, arr->field_name); RETURN (clone_); } static bool _mongoc_cursor_array_more (mongoc_cursor_t *cursor) { bool ret; mongoc_cursor_array_t *arr; bson_iter_t iter; ENTRY; arr = (mongoc_cursor_array_t *)cursor->iface_data; if (arr->has_array) { memcpy (&iter, &arr->iter, sizeof iter); ret = bson_iter_next (&iter); } else { ret = true; } RETURN (ret); } static bool _mongoc_cursor_array_error (mongoc_cursor_t *cursor, bson_error_t *error) { mongoc_cursor_array_t *arr; ENTRY; arr = (mongoc_cursor_array_t *)cursor->iface_data; if (arr->has_synthetic_bson) { return false; } else { return _mongoc_cursor_error(cursor, error); } } static mongoc_cursor_interface_t gMongocCursorArray = { _mongoc_cursor_array_clone, _mongoc_cursor_array_destroy, _mongoc_cursor_array_more, _mongoc_cursor_array_next, _mongoc_cursor_array_error, }; void _mongoc_cursor_array_init (mongoc_cursor_t *cursor, const bson_t *command, const char *field_name) { ENTRY; if (command) { bson_destroy (&cursor->query); bson_copy_to (command, &cursor->query); } cursor->iface_data = _mongoc_cursor_array_new (field_name); memcpy (&cursor->iface, &gMongocCursorArray, sizeof (mongoc_cursor_interface_t)); EXIT; } void _mongoc_cursor_array_set_bson (mongoc_cursor_t *cursor, const bson_t *bson) { mongoc_cursor_array_t *arr; ENTRY; arr = (mongoc_cursor_array_t *)cursor->iface_data; bson_copy_to(bson, &arr->bson); arr->has_array = true; arr->has_synthetic_bson = true; bson_iter_init(&arr->iter, &arr->bson); } libmongoc-1.3.1/src/mongoc/mongoc-cursor-cursorid-private.h000066400000000000000000000025771264720626300240270ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CURSOR_CURSORID_PRIVATE_H #define MONGOC_CURSOR_CURSORID_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-cursor-private.h" BSON_BEGIN_DECLS typedef struct { bool in_batch; bool in_reader; bson_iter_t batch_iter; bson_t current_doc; } mongoc_cursor_cursorid_t; bool _mongoc_cursor_cursorid_prime (mongoc_cursor_t *cursor); bool _mongoc_cursor_cursorid_next (mongoc_cursor_t *cursor, const bson_t **bson); void _mongoc_cursor_cursorid_init (mongoc_cursor_t *cursor, const bson_t *command); BSON_END_DECLS #endif /* MONGOC_CURSOR_CURSORID_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-cursor-cursorid.c000066400000000000000000000170161264720626300223440ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-cursor.h" #include "mongoc-cursor-private.h" #include "mongoc-cursor-cursorid-private.h" #include "mongoc-log.h" #include "mongoc-trace.h" #include "mongoc-error.h" #include "mongoc-util-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "cursor-cursorid" static void * _mongoc_cursor_cursorid_new (void) { mongoc_cursor_cursorid_t *cid; ENTRY; cid = (mongoc_cursor_cursorid_t *)bson_malloc0 (sizeof *cid); RETURN (cid); } static void _mongoc_cursor_cursorid_destroy (mongoc_cursor_t *cursor) { ENTRY; bson_free (cursor->iface_data); _mongoc_cursor_destroy (cursor); EXIT; } static bool _mongoc_cursor_cursorid_refresh_from_command (mongoc_cursor_t *cursor, const bson_t *command) { mongoc_cursor_cursorid_t *cid; const bson_t *bson; bson_iter_t iter, child; const char *ns; ENTRY; cid = (mongoc_cursor_cursorid_t *)cursor->iface_data; BSON_ASSERT (cid); /* server replies to find / aggregate with {cursor: {id: N, firstBatch: []}}, * to getMore command with {cursor: {id: N, nextBatch: []}}. */ if (_mongoc_cursor_run_command (cursor, command) && _mongoc_read_from_buffer (cursor, &bson) && bson_iter_init_find (&iter, bson, "cursor") && BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child)) { while (bson_iter_next (&child)) { if (BSON_ITER_IS_KEY (&child, "id")) { cursor->rpc.reply.cursor_id = bson_iter_as_int64 (&child); } else if (BSON_ITER_IS_KEY (&child, "ns")) { ns = bson_iter_utf8 (&child, &cursor->nslen); bson_strncpy (cursor->ns, ns, sizeof cursor->ns); } else if (BSON_ITER_IS_KEY (&child, "firstBatch") || BSON_ITER_IS_KEY (&child, "nextBatch")) { if (BSON_ITER_HOLDS_ARRAY (&child) && bson_iter_recurse (&child, &cid->batch_iter)) { cid->in_batch = true; } } } RETURN (true); } else { if (!cursor->error.domain) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply to %s command.", _mongoc_get_command_name (command)); } RETURN (false); } } static void _mongoc_cursor_cursorid_read_from_batch (mongoc_cursor_t *cursor, const bson_t **bson) { mongoc_cursor_cursorid_t *cid; const uint8_t *data = NULL; uint32_t data_len = 0; ENTRY; cid = (mongoc_cursor_cursorid_t *)cursor->iface_data; BSON_ASSERT (cid); if (bson_iter_next (&cid->batch_iter) && BSON_ITER_HOLDS_DOCUMENT (&cid->batch_iter)) { bson_iter_document (&cid->batch_iter, &data_len, &data); if (bson_init_static (&cid->current_doc, data, data_len)) { *bson = &cid->current_doc; } } } bool _mongoc_cursor_cursorid_prime (mongoc_cursor_t *cursor) { cursor->sent = true; return _mongoc_cursor_cursorid_refresh_from_command (cursor, &cursor->query); } static void _mongoc_cursor_prepare_getmore_command (mongoc_cursor_t *cursor, bson_t *command) { const char *collection; int collection_len; mongoc_cursor_cursorid_t *cid; cid = (mongoc_cursor_cursorid_t *)cursor->iface_data; BSON_ASSERT (cid); _mongoc_cursor_collection (cursor, &collection, &collection_len); bson_init (command); bson_append_int64 (command, "getMore", 7, mongoc_cursor_get_id (cursor)); bson_append_utf8 (command, "collection", 10, collection, collection_len); if (cursor->batch_size) { bson_append_int32 (command, "batchSize", 9, cursor->batch_size); } /* Find, getMore And killCursors Commands Spec: "In the case of a tailable cursor with awaitData == true the driver MUST provide a Cursor level option named maxAwaitTimeMS (See CRUD specification for details). The maxTimeMS option on the getMore command MUST be set to the value of the option maxAwaitTimeMS. If no maxAwaitTimeMS is specified, the driver SHOULD not set maxTimeMS on the getMore command." */ if (cursor->flags & MONGOC_QUERY_TAILABLE_CURSOR && cursor->flags & MONGOC_QUERY_AWAIT_DATA && cursor->max_await_time_ms) { bson_append_int32 (command, "maxTimeMS", 9, cursor->max_await_time_ms); } } static bool _mongoc_cursor_cursorid_get_more (mongoc_cursor_t *cursor) { mongoc_cursor_cursorid_t *cid; mongoc_server_stream_t *server_stream; bson_t command; bool ret; ENTRY; cid = (mongoc_cursor_cursorid_t *)cursor->iface_data; BSON_ASSERT (cid); server_stream = _mongoc_cursor_fetch_stream (cursor); if (!server_stream) { RETURN (false); } if (_use_find_command (cursor, server_stream)) { _mongoc_cursor_prepare_getmore_command (cursor, &command); ret = _mongoc_cursor_cursorid_refresh_from_command (cursor, &command); bson_destroy (&command); } else { ret = _mongoc_cursor_op_getmore (cursor, server_stream); cid->in_reader = ret; } mongoc_server_stream_cleanup (server_stream); RETURN (ret); } bool _mongoc_cursor_cursorid_next (mongoc_cursor_t *cursor, const bson_t **bson) { mongoc_cursor_cursorid_t *cid; bool refreshed = false; ENTRY; *bson = NULL; cid = (mongoc_cursor_cursorid_t *)cursor->iface_data; BSON_ASSERT (cid); if (!cursor->sent) { if (!_mongoc_cursor_cursorid_prime (cursor)) { GOTO (done); } } again: if (cid->in_batch) { _mongoc_cursor_cursorid_read_from_batch (cursor, bson); if (*bson) { GOTO (done); } cid->in_batch = false; } else if (cid->in_reader) { _mongoc_read_from_buffer (cursor, bson); if (*bson) { GOTO (done); } cid->in_reader = false; } if (!refreshed && mongoc_cursor_get_id (cursor)) { if (!_mongoc_cursor_cursorid_get_more (cursor)) { GOTO (done); } refreshed = true; GOTO (again); } done: RETURN (*bson ? true : false); } static mongoc_cursor_t * _mongoc_cursor_cursorid_clone (const mongoc_cursor_t *cursor) { mongoc_cursor_t *clone_; ENTRY; clone_ = _mongoc_cursor_clone (cursor); _mongoc_cursor_cursorid_init (clone_, &cursor->query); RETURN (clone_); } static mongoc_cursor_interface_t gMongocCursorCursorid = { _mongoc_cursor_cursorid_clone, _mongoc_cursor_cursorid_destroy, NULL, _mongoc_cursor_cursorid_next, }; void _mongoc_cursor_cursorid_init (mongoc_cursor_t *cursor, const bson_t *command) { ENTRY; bson_destroy (&cursor->query); bson_copy_to (command, &cursor->query); cursor->iface_data = _mongoc_cursor_cursorid_new (); memcpy (&cursor->iface, &gMongocCursorCursorid, sizeof (mongoc_cursor_interface_t)); EXIT; } libmongoc-1.3.1/src/mongoc/mongoc-cursor-private.h000066400000000000000000000135441264720626300221730ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CURSOR_PRIVATE_H #define MONGOC_CURSOR_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-client.h" #include "mongoc-buffer-private.h" #include "mongoc-rpc-private.h" #include "mongoc-server-stream-private.h" BSON_BEGIN_DECLS typedef struct _mongoc_cursor_interface_t mongoc_cursor_interface_t; struct _mongoc_cursor_interface_t { mongoc_cursor_t *(*clone) (const mongoc_cursor_t *cursor); void (*destroy) (mongoc_cursor_t *cursor); bool (*more) (mongoc_cursor_t *cursor); bool (*next) (mongoc_cursor_t *cursor, const bson_t **bson); bool (*error) (mongoc_cursor_t *cursor, bson_error_t *error); void (*get_host) (mongoc_cursor_t *cursor, mongoc_host_list_t *host); }; struct _mongoc_cursor_t { mongoc_client_t *client; uint32_t hint; uint32_t stamp; unsigned is_command : 1; unsigned sent : 1; unsigned done : 1; unsigned end_of_event : 1; unsigned has_fields : 1; unsigned in_exhaust : 1; bson_t query; bson_t fields; mongoc_read_concern_t *read_concern; mongoc_read_prefs_t *read_prefs; mongoc_query_flags_t flags; uint32_t skip; uint32_t limit; uint32_t count; uint32_t batch_size; uint32_t max_await_time_ms; char ns [140]; uint32_t nslen; uint32_t dblen; bson_error_t error; mongoc_rpc_t rpc; mongoc_buffer_t buffer; bson_reader_t *reader; const bson_t *current; mongoc_cursor_interface_t iface; void *iface_data; }; mongoc_cursor_t * _mongoc_cursor_new (mongoc_client_t *client, const char *db_and_collection, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, bool is_command, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern); mongoc_cursor_t *_mongoc_cursor_clone (const mongoc_cursor_t *cursor); void _mongoc_cursor_destroy (mongoc_cursor_t *cursor); bool _mongoc_read_from_buffer (mongoc_cursor_t *cursor, const bson_t **bson); bool _use_find_command (const mongoc_cursor_t *cursor, const mongoc_server_stream_t *server_stream); mongoc_server_stream_t * _mongoc_cursor_fetch_stream (mongoc_cursor_t *cursor); void _mongoc_cursor_collection (const mongoc_cursor_t *cursor, const char **collection, int *collection_len); bool _mongoc_cursor_op_getmore (mongoc_cursor_t *cursor, mongoc_server_stream_t *server_stream); bool _mongoc_cursor_run_command (mongoc_cursor_t *cursor, const bson_t *command); bool _mongoc_cursor_more (mongoc_cursor_t *cursor); bool _mongoc_cursor_next (mongoc_cursor_t *cursor, const bson_t **bson); bool _mongoc_cursor_error (mongoc_cursor_t *cursor, bson_error_t *error); void _mongoc_cursor_get_host (mongoc_cursor_t *cursor, mongoc_host_list_t *host); BSON_END_DECLS #endif /* MONGOC_CURSOR_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-cursor-transform-private.h000066400000000000000000000035141264720626300242000ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CURSOR_FILTER_PRIVATE_H #define MONGOC_CURSOR_FILTER_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-cursor-private.h" BSON_BEGIN_DECLS typedef enum { MONGO_CURSOR_TRANSFORM_DROP, MONGO_CURSOR_TRANSFORM_PASS, MONGO_CURSOR_TRANSFORM_MUTATE, } mongoc_cursor_transform_mode_t; typedef mongoc_cursor_transform_mode_t (*mongoc_cursor_transform_filter_t)(const bson_t *bson, void *ctx); typedef void (*mongoc_cursor_transform_mutate_t)(const bson_t *bson, bson_t *out, void *ctx); typedef void (*mongoc_cursor_transform_dtor_t)(void *ctx); void _mongoc_cursor_transform_init (mongoc_cursor_t *cursor, mongoc_cursor_transform_filter_t filter, mongoc_cursor_transform_mutate_t mutate, mongoc_cursor_transform_dtor_t dtor, void *ctx); BSON_END_DECLS #endif /* MONGOC_CURSOR_FILTER_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-cursor-transform.c000066400000000000000000000101731264720626300225220ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-cursor.h" #include "mongoc-cursor-transform-private.h" #include "mongoc-cursor-private.h" #include "mongoc-client-private.h" #include "mongoc-counters-private.h" #include "mongoc-error.h" #include "mongoc-log.h" #include "mongoc-opcode.h" #include "mongoc-trace.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "cursor-transform" typedef struct { mongoc_cursor_transform_filter_t filter; mongoc_cursor_transform_mutate_t mutate; mongoc_cursor_transform_dtor_t dtor; void *ctx; bson_t tmp; } mongoc_cursor_transform_t; static void * _mongoc_cursor_transform_new (mongoc_cursor_transform_filter_t filter, mongoc_cursor_transform_mutate_t mutate, mongoc_cursor_transform_dtor_t dtor, void *ctx) { mongoc_cursor_transform_t *transform; ENTRY; transform = (mongoc_cursor_transform_t *)bson_malloc0 (sizeof *transform); transform->filter = filter; transform->mutate = mutate; transform->dtor = dtor; transform->ctx = ctx; bson_init (&transform->tmp); RETURN (transform); } static void _mongoc_cursor_transform_destroy (mongoc_cursor_t *cursor) { mongoc_cursor_transform_t *transform; ENTRY; transform = (mongoc_cursor_transform_t *)cursor->iface_data; if (transform->dtor) { transform->dtor (transform->ctx); } bson_destroy (&transform->tmp); bson_free (cursor->iface_data); _mongoc_cursor_destroy (cursor); EXIT; } static bool _mongoc_cursor_transform_next (mongoc_cursor_t *cursor, const bson_t **bson) { mongoc_cursor_transform_t *transform; ENTRY; transform = (mongoc_cursor_transform_t *)cursor->iface_data; for (;; ) { if (!_mongoc_cursor_next (cursor, bson)) { RETURN (false); } switch (transform->filter (*bson, transform->ctx)) { case MONGO_CURSOR_TRANSFORM_DROP: break; case MONGO_CURSOR_TRANSFORM_PASS: RETURN (true); break; case MONGO_CURSOR_TRANSFORM_MUTATE: bson_reinit (&transform->tmp); transform->mutate (*bson, &transform->tmp, transform->ctx); *bson = &transform->tmp; RETURN (true); break; default: abort (); break; } } } static mongoc_cursor_t * _mongoc_cursor_transform_clone (const mongoc_cursor_t *cursor) { mongoc_cursor_transform_t *transform; mongoc_cursor_t *clone_; ENTRY; transform = (mongoc_cursor_transform_t *)cursor->iface_data; clone_ = _mongoc_cursor_clone (cursor); _mongoc_cursor_transform_init (clone_, transform->filter, transform->mutate, transform->dtor, transform->ctx); RETURN (clone_); } static mongoc_cursor_interface_t gMongocCursorArray = { _mongoc_cursor_transform_clone, _mongoc_cursor_transform_destroy, NULL, _mongoc_cursor_transform_next, }; void _mongoc_cursor_transform_init (mongoc_cursor_t *cursor, mongoc_cursor_transform_filter_t filter, mongoc_cursor_transform_mutate_t mutate, mongoc_cursor_transform_dtor_t dtor, void *ctx) { ENTRY; cursor->iface_data = _mongoc_cursor_transform_new (filter, mutate, dtor, ctx); memcpy (&cursor->iface, &gMongocCursorArray, sizeof (mongoc_cursor_interface_t)); EXIT; } libmongoc-1.3.1/src/mongoc/mongoc-cursor.c000066400000000000000000001025361264720626300205160ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-cursor.h" #include "mongoc-cursor-private.h" #include "mongoc-client-private.h" #include "mongoc-counters-private.h" #include "mongoc-error.h" #include "mongoc-log.h" #include "mongoc-trace.h" #include "mongoc-cursor-cursorid-private.h" #include "mongoc-read-concern-private.h" #include "mongoc-util-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "cursor" #define CURSOR_FAILED(cursor_) ((cursor_)->error.domain != 0) static const bson_t * _mongoc_cursor_op_query (mongoc_cursor_t *cursor, mongoc_server_stream_t *server_stream); static const bson_t * _mongoc_cursor_find_command (mongoc_cursor_t *cursor); static int32_t _mongoc_n_return (mongoc_cursor_t * cursor) { if (cursor->is_command) { /* commands always have n_return of 1 */ return 1; } else if (cursor->limit) { int32_t remaining = cursor->limit - cursor->count; BSON_ASSERT (remaining > 0); if (cursor->batch_size) { return BSON_MIN ((int32_t) cursor->batch_size, remaining); } else { /* batch_size 0 means accept the default */ return remaining; } } else { return cursor->batch_size; } } mongoc_cursor_t * _mongoc_cursor_new (mongoc_client_t *client, const char *db_and_collection, mongoc_query_flags_t qflags, uint32_t skip, uint32_t limit, uint32_t batch_size, bool is_command, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern) { mongoc_cursor_t *cursor; bson_iter_t iter; int flags = qflags; const char *dot; ENTRY; BSON_ASSERT (client); BSON_ASSERT (db_and_collection); if (!read_concern) { read_concern = client->read_concern; } if (!read_prefs) { read_prefs = client->read_prefs; } cursor = (mongoc_cursor_t *)bson_malloc0 (sizeof *cursor); /* * Cursors execute their query lazily. This sadly means that we must copy * some extra data around between the bson_t structures. This should be * small in most cases, so it reduces to a pure memcpy. The benefit to this * design is simplified error handling by API consumers. */ cursor->client = client; bson_strncpy (cursor->ns, db_and_collection, sizeof cursor->ns); cursor->nslen = (uint32_t)bson_strnlen (cursor->ns, sizeof cursor->ns); dot = strstr (db_and_collection, "."); if (dot) { cursor->dblen = (uint32_t)(dot - db_and_collection); } else { /* a database name with no collection name */ cursor->dblen = cursor->nslen; } cursor->flags = (mongoc_query_flags_t)flags; cursor->skip = skip; cursor->limit = limit; cursor->batch_size = batch_size; cursor->is_command = is_command; cursor->has_fields = !!fields; #define MARK_FAILED(c) \ do { \ bson_init (&(c)->query); \ bson_init (&(c)->fields); \ (c)->done = true; \ (c)->end_of_event = true; \ (c)->sent = true; \ } while (0) /* we can't have exhaust queries with limits */ if ((flags & MONGOC_QUERY_EXHAUST) && limit) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot specify MONGOC_QUERY_EXHAUST and set a limit."); MARK_FAILED (cursor); GOTO (finish); } /* we can't have exhaust queries with sharded clusters */ if ((flags & MONGOC_QUERY_EXHAUST) && (client->topology->description.type == MONGOC_TOPOLOGY_SHARDED)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot specify MONGOC_QUERY_EXHAUST with sharded cluster."); MARK_FAILED (cursor); GOTO (finish); } /* * Check types of various optional parameters. */ if (query && !is_command) { if (bson_iter_init_find (&iter, query, "$explain") && !(BSON_ITER_HOLDS_BOOL (&iter) || BSON_ITER_HOLDS_INT32 (&iter))) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "$explain must be a boolean."); MARK_FAILED (cursor); GOTO (finish); } if (bson_iter_init_find (&iter, query, "$snapshot") && !BSON_ITER_HOLDS_BOOL (&iter) && !BSON_ITER_HOLDS_INT32 (&iter)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "$snapshot must be a boolean."); MARK_FAILED (cursor); GOTO (finish); } } /* * Check if we have a mixed top-level query and dollar keys such * as $orderby. This is not allowed (you must use {$query:{}}. */ if (query && bson_iter_init (&iter, query)) { bool found_dollar = false; bool found_non_dollar = false; while (bson_iter_next (&iter)) { if (bson_iter_key (&iter)[0] == '$') { found_dollar = true; } else { found_non_dollar = true; } } if (found_dollar && found_non_dollar) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot mix top-level query with dollar keys such " "as $orderby. Use {$query: {},...} instead."); MARK_FAILED (cursor); GOTO (finish); } } /* don't use MARK_FAILED after this, you'll leak cursor->query */ if (query) { bson_copy_to(query, &cursor->query); } else { bson_init(&cursor->query); } if (fields) { bson_copy_to(fields, &cursor->fields); } else { bson_init(&cursor->fields); } if (read_prefs) { cursor->read_prefs = mongoc_read_prefs_copy (read_prefs); } if (read_concern) { cursor->read_concern = mongoc_read_concern_copy (read_concern); } _mongoc_buffer_init(&cursor->buffer, NULL, 0, NULL, NULL); finish: mongoc_counter_cursors_active_inc(); RETURN (cursor); } void mongoc_cursor_destroy (mongoc_cursor_t *cursor) { ENTRY; BSON_ASSERT(cursor); if (cursor->iface.destroy) { cursor->iface.destroy(cursor); } else { _mongoc_cursor_destroy(cursor); } EXIT; } void _mongoc_cursor_destroy (mongoc_cursor_t *cursor) { char db[MONGOC_NAMESPACE_MAX]; ENTRY; BSON_ASSERT (cursor); if (cursor->in_exhaust) { cursor->client->in_exhaust = false; if (!cursor->done) { /* The only way to stop an exhaust cursor is to kill the connection */ mongoc_cluster_disconnect_node (&cursor->client->cluster, cursor->hint); } } else if (cursor->rpc.reply.cursor_id) { bson_strncpy (db, cursor->ns, cursor->dblen + 1); _mongoc_client_kill_cursor(cursor->client, cursor->hint, cursor->rpc.reply.cursor_id, db, cursor->ns + cursor->dblen + 1); } if (cursor->reader) { bson_reader_destroy(cursor->reader); cursor->reader = NULL; } bson_destroy(&cursor->query); bson_destroy(&cursor->fields); _mongoc_buffer_destroy(&cursor->buffer); mongoc_read_prefs_destroy(cursor->read_prefs); mongoc_read_concern_destroy(cursor->read_concern); bson_free(cursor); mongoc_counter_cursors_active_dec(); mongoc_counter_cursors_disposed_inc(); EXIT; } mongoc_server_stream_t * _mongoc_cursor_fetch_stream (mongoc_cursor_t *cursor) { mongoc_server_stream_t *server_stream; ENTRY; if (cursor->hint) { server_stream = mongoc_cluster_stream_for_server (&cursor->client->cluster, cursor->hint, true /* reconnect_ok */, &cursor->error); } else { server_stream = mongoc_cluster_stream_for_reads (&cursor->client->cluster, cursor->read_prefs, &cursor->error); if (server_stream) { cursor->hint = server_stream->sd->id; } } RETURN (server_stream); } bool _use_find_command (const mongoc_cursor_t *cursor, const mongoc_server_stream_t *server_stream) { /* Find, getMore And killCursors Commands Spec: "the find command cannot be * used to execute other commands" and "the find command does not support the * exhaust flag." */ return server_stream->sd->max_wire_version >= WIRE_VERSION_FIND_CMD && !cursor->is_command && !(cursor->flags & MONGOC_QUERY_EXHAUST); } static const bson_t * _mongoc_cursor_initial_query (mongoc_cursor_t *cursor) { mongoc_server_stream_t *server_stream; const bson_t *b = NULL; ENTRY; BSON_ASSERT (cursor); server_stream = _mongoc_cursor_fetch_stream (cursor); if (!server_stream) { GOTO (done); } if (_use_find_command (cursor, server_stream)) { b = _mongoc_cursor_find_command (cursor); } else { /* When the user explicitly provides a readConcern -- but the server * doesn't support readConcern, we must error: * https://github.com/mongodb/specifications/blob/master/source/read-write-concern/read-write-concern.rst#errors-1 */ if (cursor->read_concern->level != NULL && server_stream->sd->max_wire_version < WIRE_VERSION_READ_CONCERN) { bson_set_error (&cursor->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support readConcern"); } else { b = _mongoc_cursor_op_query (cursor, server_stream); } } done: /* no-op if server_stream is NULL */ mongoc_server_stream_cleanup (server_stream); if (!b) { cursor->done = true; } RETURN (b); } static const bson_t * _mongoc_cursor_op_query (mongoc_cursor_t *cursor, mongoc_server_stream_t *server_stream) { mongoc_apply_read_prefs_result_t result = READ_PREFS_RESULT_INIT; mongoc_rpc_t rpc; uint32_t request_id; const bson_t *bson = NULL; ENTRY; cursor->sent = true; rpc.query.msg_len = 0; rpc.query.request_id = 0; rpc.query.response_to = 0; rpc.query.opcode = MONGOC_OPCODE_QUERY; rpc.query.flags = cursor->flags; rpc.query.collection = cursor->ns; rpc.query.skip = cursor->skip; if ((cursor->flags & MONGOC_QUERY_TAILABLE_CURSOR)) { rpc.query.n_return = 0; } else { rpc.query.n_return = _mongoc_n_return(cursor); } if (cursor->has_fields) { rpc.query.fields = bson_get_data (&cursor->fields); } else { rpc.query.fields = NULL; } apply_read_preferences (cursor->read_prefs, server_stream, &cursor->query, cursor->flags, &result); rpc.query.query = bson_get_data (result.query_with_read_prefs); rpc.query.flags = result.flags; if (!mongoc_cluster_sendv_to_server (&cursor->client->cluster, &rpc, 1, server_stream, NULL, &cursor->error)) { GOTO (failure); } request_id = BSON_UINT32_FROM_LE (rpc.header.request_id); _mongoc_buffer_clear(&cursor->buffer, false); if (!_mongoc_client_recv(cursor->client, &cursor->rpc, &cursor->buffer, server_stream, &cursor->error)) { GOTO (failure); } if (cursor->rpc.header.opcode != MONGOC_OPCODE_REPLY) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid opcode. Expected %d, got %d.", MONGOC_OPCODE_REPLY, cursor->rpc.header.opcode); GOTO (failure); } if (cursor->rpc.header.response_to != request_id) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid response_to for query. Expected %d, got %d.", request_id, cursor->rpc.header.response_to); GOTO (failure); } if (cursor->is_command) { if (_mongoc_rpc_parse_command_error (&cursor->rpc, &cursor->error)) { GOTO (failure); } } else { if (_mongoc_rpc_parse_query_error (&cursor->rpc, &cursor->error)) { GOTO (failure); } } if (cursor->reader) { bson_reader_destroy (cursor->reader); } cursor->reader = bson_reader_new_from_data( cursor->rpc.reply.documents, (size_t) cursor->rpc.reply.documents_len); if ((cursor->flags & MONGOC_QUERY_EXHAUST)) { cursor->in_exhaust = true; cursor->client->in_exhaust = true; } cursor->done = false; cursor->end_of_event = false; cursor->sent = true; _mongoc_read_from_buffer (cursor, &bson); apply_read_prefs_result_cleanup (&result); RETURN (bson); failure: cursor->done = true; apply_read_prefs_result_cleanup (&result); RETURN (false); } bool _mongoc_cursor_run_command (mongoc_cursor_t *cursor, const bson_t *command) { mongoc_cluster_t *cluster; mongoc_server_stream_t *server_stream; char cmd_ns[MONGOC_NAMESPACE_MAX]; mongoc_apply_read_prefs_result_t read_prefs_result = READ_PREFS_RESULT_INIT; bool ret = false; bson_t bson; mongoc_rpc_t rpc; ENTRY; cluster = &cursor->client->cluster; server_stream = _mongoc_cursor_fetch_stream (cursor); if (!server_stream) { GOTO (done); } _mongoc_buffer_clear (&cursor->buffer, false); bson_snprintf (cmd_ns, sizeof cmd_ns, "%.*s.$cmd", cursor->dblen, cursor->ns); apply_read_preferences (cursor->read_prefs, server_stream, command, cursor->flags, &read_prefs_result); _mongoc_rpc_prep_command (&rpc, cmd_ns, read_prefs_result.query_with_read_prefs, read_prefs_result.flags); if (!mongoc_cluster_run_command_rpc (cluster, server_stream->stream, _mongoc_get_command_name (&cursor->query), &rpc, &cursor->rpc, &cursor->buffer, &cursor->error)) { GOTO (done); } /* static-init "bson" to point into buffer */ if (!_mongoc_rpc_reply_get_first (&cursor->rpc.reply, &bson)) { bson_set_error (&cursor->error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Failed to decode reply BSON document."); GOTO (done); } if (_mongoc_rpc_parse_command_error (&cursor->rpc, &cursor->error)) { GOTO (done); } if (cursor->reader) { bson_reader_destroy (cursor->reader); } cursor->reader = bson_reader_new_from_data ( cursor->rpc.reply.documents, (size_t)cursor->rpc.reply.documents_len); ret = true; done: apply_read_prefs_result_cleanup (&read_prefs_result); mongoc_server_stream_cleanup (server_stream); return ret; } static bool _invalid_field (const char *query_field, mongoc_cursor_t *cursor) { if (query_field[0] == '\0') { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "empty string is not a valid query operator"); return true; } return false; } static bool _translate_query_opt (const char *query_field, const char **cmd_field, int *len) { if (query_field[0] != '$') { *cmd_field = query_field; *len = -1; return true; } /* strip the leading '$' */ query_field++; if (!strcmp ("query", query_field)) { *cmd_field = "filter"; *len = 6; } else if (!strcmp ("orderby", query_field)) { *cmd_field = "sort"; *len = 4; } else if (!strcmp ("showDiskLoc", query_field)) { /* <= MongoDb 3.0 */ *cmd_field = "showRecordId"; *len = 12; } else if (!strcmp("hint", query_field)) { *cmd_field = "hint"; *len = 4; } else if (!strcmp("comment", query_field)) { *cmd_field = "comment"; *len = 7; } else if (!strcmp("maxScan", query_field)) { *cmd_field = "maxScan"; *len = 7; } else if (!strcmp("maxTimeMS", query_field)) { *cmd_field = "maxTimeMS"; *len = 9; } else if (!strcmp("max", query_field)) { *cmd_field = "max"; *len = 3; } else if (!strcmp("min", query_field)) { *cmd_field = "min"; *len = 3; } else if (!strcmp("returnKey", query_field)) { *cmd_field = "returnKey"; *len = 9; } else if (!strcmp("snapshot", query_field)) { *cmd_field = "snapshot"; *len = 8; } else { /* not a special command field, must be a query operator like $or */ return false; } return true; } static void _mongoc_cursor_prepare_find_command_flags (mongoc_cursor_t *cursor, bson_t *command) { mongoc_query_flags_t flags = cursor->flags; if (flags & MONGOC_QUERY_TAILABLE_CURSOR) { bson_append_bool (command, "tailable", 8, true); } if (flags & MONGOC_QUERY_OPLOG_REPLAY) { bson_append_bool (command, "oplogReplay", 11, true); } if (flags & MONGOC_QUERY_NO_CURSOR_TIMEOUT) { bson_append_bool (command, "noCursorTimeout", 15, true); } if (flags & MONGOC_QUERY_AWAIT_DATA) { bson_append_bool (command, "awaitData", 9, true); } if (flags & MONGOC_QUERY_PARTIAL) { bson_append_bool (command, "allowPartialResults", 19, true); } } void _mongoc_cursor_collection (const mongoc_cursor_t *cursor, const char **collection, int *collection_len) { /* ns is like "db.collection". Collection name is located past the ".". */ *collection = cursor->ns + (cursor->dblen + 1); /* Collection name's length is ns length, minus length of db name and ".". */ *collection_len = cursor->nslen - cursor->dblen - 1; BSON_ASSERT (*collection_len > 0); } static bool _mongoc_cursor_prepare_find_command (mongoc_cursor_t *cursor, bson_t *command) { const char *collection; int collection_len; bson_iter_t iter; const char *command_field; int len; const bson_value_t *value; _mongoc_cursor_collection (cursor, &collection, &collection_len); bson_append_utf8 (command, "find", 4, collection, collection_len); if (bson_empty0 (&cursor->query)) { /* Find, getMore And killCursors Commands Spec: filter "MUST be included * in the command". */ bson_t empty = BSON_INITIALIZER; bson_append_document (command, "filter", 6, &empty); } else if (bson_has_field (&cursor->query, "$query")) { bson_iter_init (&iter, &cursor->query); while (bson_iter_next (&iter)) { if (_invalid_field (bson_iter_key (&iter), cursor)) { return false; } value = bson_iter_value (&iter); if (_translate_query_opt (bson_iter_key (&iter), &command_field, &len)) { bson_append_value (command, command_field, len, value); } else { bson_append_value (command, bson_iter_key (&iter), -1, value); } } } else if (bson_has_field (&cursor->query, "filter")) { bson_concat (command, &cursor->query); } else { /* cursor->query has no "$query", use it as the filter */ bson_append_document (command, "filter", 6, &cursor->query); } if (!bson_empty0 (&cursor->fields)) { bson_append_document (command, "projection", 10, &cursor->fields); } if (cursor->skip) { bson_append_int64 (command, "skip", 4, cursor->skip); } if (cursor->limit) { bson_append_int64 (command, "limit", 5, cursor->limit); } if (cursor->batch_size) { bson_append_int32 (command, "batchSize", 9, cursor->batch_size); } if (cursor->read_concern->level != NULL) { const bson_t *read_concern_bson; read_concern_bson = _mongoc_read_concern_get_bson (cursor->read_concern); BSON_APPEND_DOCUMENT (command, "readConcern", read_concern_bson); } _mongoc_cursor_prepare_find_command_flags (cursor, command); return true; } static const bson_t * _mongoc_cursor_find_command (mongoc_cursor_t *cursor) { bson_t command = BSON_INITIALIZER; const bson_t *bson = NULL; ENTRY; if (!_mongoc_cursor_prepare_find_command (cursor, &command)) { RETURN (NULL); } _mongoc_cursor_cursorid_init (cursor, &command); bson_destroy (&command); BSON_ASSERT (cursor->iface.next); _mongoc_cursor_cursorid_next (cursor, &bson); RETURN (bson); } static const bson_t * _mongoc_cursor_get_more (mongoc_cursor_t *cursor) { mongoc_server_stream_t *server_stream; const bson_t *b = NULL; ENTRY; BSON_ASSERT (cursor); server_stream = _mongoc_cursor_fetch_stream (cursor); if (!server_stream) { GOTO (failure); } if (!cursor->in_exhaust && !cursor->rpc.reply.cursor_id) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "No valid cursor was provided."); GOTO (failure); } if (!_mongoc_cursor_op_getmore (cursor, server_stream)) { GOTO (failure); } mongoc_server_stream_cleanup (server_stream); if (cursor->reader) { _mongoc_read_from_buffer (cursor, &b); } RETURN (b); failure: cursor->done = true; mongoc_server_stream_cleanup (server_stream); RETURN (NULL); } bool _mongoc_cursor_op_getmore (mongoc_cursor_t *cursor, mongoc_server_stream_t *server_stream) { mongoc_rpc_t rpc; uint32_t request_id; bool ret = false; ENTRY; if (cursor->in_exhaust) { request_id = (uint32_t) cursor->rpc.header.request_id; } else { rpc.get_more.cursor_id = cursor->rpc.reply.cursor_id; rpc.get_more.msg_len = 0; rpc.get_more.request_id = 0; rpc.get_more.response_to = 0; rpc.get_more.opcode = MONGOC_OPCODE_GET_MORE; rpc.get_more.zero = 0; rpc.get_more.collection = cursor->ns; if ((cursor->flags & MONGOC_QUERY_TAILABLE_CURSOR)) { rpc.get_more.n_return = 0; } else { rpc.get_more.n_return = _mongoc_n_return(cursor); } if (!mongoc_cluster_sendv_to_server (&cursor->client->cluster, &rpc, 1, server_stream, NULL, &cursor->error)) { GOTO (done); } request_id = BSON_UINT32_FROM_LE (rpc.header.request_id); } _mongoc_buffer_clear (&cursor->buffer, false); if (!_mongoc_client_recv (cursor->client, &cursor->rpc, &cursor->buffer, server_stream, &cursor->error)) { GOTO (done); } if (cursor->rpc.header.opcode != MONGOC_OPCODE_REPLY) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid opcode. Expected %d, got %d.", MONGOC_OPCODE_REPLY, cursor->rpc.header.opcode); GOTO (done); } if (cursor->rpc.header.response_to != request_id) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid response_to for getmore. Expected %d, got %d.", request_id, cursor->rpc.header.response_to); GOTO (done); } if (_mongoc_rpc_parse_query_error (&cursor->rpc, &cursor->error)) { GOTO (done); } if (cursor->reader) { bson_reader_destroy (cursor->reader); } cursor->reader = bson_reader_new_from_data ( cursor->rpc.reply.documents, (size_t)cursor->rpc.reply.documents_len); ret = true; done: RETURN (ret); } bool mongoc_cursor_error (mongoc_cursor_t *cursor, bson_error_t *error) { bool ret; ENTRY; BSON_ASSERT(cursor); if (cursor->iface.error) { ret = cursor->iface.error(cursor, error); } else { ret = _mongoc_cursor_error(cursor, error); } RETURN(ret); } bool _mongoc_cursor_error (mongoc_cursor_t *cursor, bson_error_t *error) { ENTRY; BSON_ASSERT (cursor); if (BSON_UNLIKELY(CURSOR_FAILED (cursor))) { bson_set_error(error, cursor->error.domain, cursor->error.code, "%s", cursor->error.message); RETURN(true); } RETURN(false); } bool mongoc_cursor_next (mongoc_cursor_t *cursor, const bson_t **bson) { bool ret; ENTRY; BSON_ASSERT(cursor); BSON_ASSERT(bson); TRACE ("cursor_id(%"PRId64")", cursor->rpc.reply.cursor_id); if (bson) { *bson = NULL; } if (CURSOR_FAILED (cursor)) { return false; } /* * We cannot proceed if another cursor is receiving results in exhaust mode. */ if (cursor->client->in_exhaust && !cursor->in_exhaust) { bson_set_error (&cursor->error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_IN_EXHAUST, "Another cursor derived from this client is in exhaust."); RETURN (false); } if (cursor->iface.next) { ret = cursor->iface.next(cursor, bson); } else { ret = _mongoc_cursor_next(cursor, bson); } cursor->current = *bson; cursor->count++; RETURN(ret); } bool _mongoc_read_from_buffer (mongoc_cursor_t *cursor, const bson_t **bson) { bool eof = false; BSON_ASSERT (cursor->reader); *bson = bson_reader_read (cursor->reader, &eof); cursor->end_of_event = eof ? 1 : 0; return *bson ? true : false; } bool _mongoc_cursor_next (mongoc_cursor_t *cursor, const bson_t **bson) { const bson_t *b = NULL; ENTRY; BSON_ASSERT (cursor); if (bson) { *bson = NULL; } if (cursor->done || CURSOR_FAILED (cursor)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot advance a completed or failed cursor."); RETURN (false); } /* * If we reached our limit, make sure we mark this as done and do not try to * make further progress. */ if (cursor->limit && cursor->count >= cursor->limit) { cursor->done = true; RETURN (false); } /* * Try to read the next document from the reader if it exists, we might * get NULL back and EOF, in which case we need to submit a getmore. */ if (cursor->reader) { _mongoc_read_from_buffer (cursor, &b); if (b) { GOTO (complete); } } /* * Check to see if we need to send a GET_MORE for more results. */ if (!cursor->sent) { b = _mongoc_cursor_initial_query (cursor); } else if (BSON_UNLIKELY (cursor->end_of_event) && cursor->rpc.reply.cursor_id) { b = _mongoc_cursor_get_more (cursor); } complete: cursor->done = (cursor->end_of_event && ((cursor->in_exhaust && !cursor->rpc.reply.cursor_id) || (!b && !(cursor->flags & MONGOC_QUERY_TAILABLE_CURSOR)))); if (bson) { *bson = b; } RETURN (!!b); } bool mongoc_cursor_more (mongoc_cursor_t *cursor) { bool ret; ENTRY; BSON_ASSERT(cursor); if (cursor->iface.more) { ret = cursor->iface.more(cursor); } else { ret = _mongoc_cursor_more(cursor); } RETURN(ret); } bool _mongoc_cursor_more (mongoc_cursor_t *cursor) { BSON_ASSERT (cursor); if (CURSOR_FAILED (cursor)) { return false; } return (!cursor->sent || cursor->rpc.reply.cursor_id || !cursor->end_of_event); } void mongoc_cursor_get_host (mongoc_cursor_t *cursor, mongoc_host_list_t *host) { BSON_ASSERT(cursor); BSON_ASSERT(host); if (cursor->iface.get_host) { cursor->iface.get_host(cursor, host); } else { _mongoc_cursor_get_host(cursor, host); } EXIT; } void _mongoc_cursor_get_host (mongoc_cursor_t *cursor, mongoc_host_list_t *host) { mongoc_server_description_t *description; BSON_ASSERT (cursor); BSON_ASSERT (host); memset(host, 0, sizeof *host); if (!cursor->hint) { MONGOC_WARNING("%s(): Must send query before fetching peer.", BSON_FUNC); return; } description = mongoc_topology_server_by_id(cursor->client->topology, cursor->hint, &cursor->error); if (!description) { return; } *host = description->host; mongoc_server_description_destroy (description); return; } mongoc_cursor_t * mongoc_cursor_clone (const mongoc_cursor_t *cursor) { mongoc_cursor_t *ret; BSON_ASSERT(cursor); if (cursor->iface.clone) { ret = cursor->iface.clone(cursor); } else { ret = _mongoc_cursor_clone(cursor); } RETURN(ret); } mongoc_cursor_t * _mongoc_cursor_clone (const mongoc_cursor_t *cursor) { mongoc_cursor_t *_clone; ENTRY; BSON_ASSERT (cursor); _clone = (mongoc_cursor_t *)bson_malloc0 (sizeof *_clone); _clone->client = cursor->client; _clone->is_command = cursor->is_command; _clone->flags = cursor->flags; _clone->skip = cursor->skip; _clone->batch_size = cursor->batch_size; _clone->limit = cursor->limit; _clone->nslen = cursor->nslen; _clone->dblen = cursor->dblen; _clone->has_fields = cursor->has_fields; if (cursor->read_prefs) { _clone->read_prefs = mongoc_read_prefs_copy (cursor->read_prefs); } if (cursor->read_concern) { _clone->read_concern = mongoc_read_concern_copy (cursor->read_concern); } bson_copy_to (&cursor->query, &_clone->query); bson_copy_to (&cursor->fields, &_clone->fields); bson_strncpy (_clone->ns, cursor->ns, sizeof _clone->ns); _mongoc_buffer_init (&_clone->buffer, NULL, 0, NULL, NULL); mongoc_counter_cursors_active_inc (); RETURN (_clone); } /* *-------------------------------------------------------------------------- * * mongoc_cursor_is_alive -- * * Checks to see if a cursor is alive. * * This is primarily useful with tailable cursors. * * Returns: * true if the cursor is alive. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool mongoc_cursor_is_alive (const mongoc_cursor_t *cursor) /* IN */ { BSON_ASSERT (cursor); return (!cursor->sent || (!CURSOR_FAILED (cursor) && !cursor->done && (cursor->rpc.header.opcode == MONGOC_OPCODE_REPLY) && cursor->rpc.reply.cursor_id)); } const bson_t * mongoc_cursor_current (const mongoc_cursor_t *cursor) /* IN */ { BSON_ASSERT (cursor); return cursor->current; } void mongoc_cursor_set_batch_size (mongoc_cursor_t *cursor, uint32_t batch_size) { BSON_ASSERT (cursor); cursor->batch_size = batch_size; } uint32_t mongoc_cursor_get_batch_size (const mongoc_cursor_t *cursor) { BSON_ASSERT (cursor); return cursor->batch_size; } uint32_t mongoc_cursor_get_hint (const mongoc_cursor_t *cursor) { BSON_ASSERT (cursor); return cursor->hint; } int64_t mongoc_cursor_get_id (const mongoc_cursor_t *cursor) { BSON_ASSERT(cursor); return cursor->rpc.reply.cursor_id; } void mongoc_cursor_set_max_await_time_ms (mongoc_cursor_t *cursor, uint32_t max_await_time_ms) { BSON_ASSERT (cursor); if (!cursor->sent) { cursor->max_await_time_ms = max_await_time_ms; } } uint32_t mongoc_cursor_get_max_await_time_ms (const mongoc_cursor_t *cursor) { BSON_ASSERT (cursor); return cursor->max_await_time_ms; } libmongoc-1.3.1/src/mongoc/mongoc-cursor.h000066400000000000000000000050541264720626300205200ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_CURSOR_H #define MONGOC_CURSOR_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-host-list.h" BSON_BEGIN_DECLS typedef struct _mongoc_cursor_t mongoc_cursor_t; mongoc_cursor_t *mongoc_cursor_clone (const mongoc_cursor_t *cursor) BSON_GNUC_WARN_UNUSED_RESULT; void mongoc_cursor_destroy (mongoc_cursor_t *cursor); bool mongoc_cursor_more (mongoc_cursor_t *cursor); bool mongoc_cursor_next (mongoc_cursor_t *cursor, const bson_t **bson); bool mongoc_cursor_error (mongoc_cursor_t *cursor, bson_error_t *error); void mongoc_cursor_get_host (mongoc_cursor_t *cursor, mongoc_host_list_t *host); bool mongoc_cursor_is_alive (const mongoc_cursor_t *cursor); const bson_t *mongoc_cursor_current (const mongoc_cursor_t *cursor); void mongoc_cursor_set_batch_size (mongoc_cursor_t *cursor, uint32_t batch_size); uint32_t mongoc_cursor_get_batch_size (const mongoc_cursor_t *cursor); uint32_t mongoc_cursor_get_hint (const mongoc_cursor_t *cursor); int64_t mongoc_cursor_get_id (const mongoc_cursor_t *cursor); void mongoc_cursor_set_max_await_time_ms (mongoc_cursor_t *cursor, uint32_t max_await_time_ms); uint32_t mongoc_cursor_get_max_await_time_ms (const mongoc_cursor_t *cursor); BSON_END_DECLS #endif /* MONGOC_CURSOR_H */ libmongoc-1.3.1/src/mongoc/mongoc-database-private.h000066400000000000000000000040471264720626300224200ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_DATABASE_PRIVATE_H #define MONGOC_DATABASE_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-client.h" #include "mongoc-read-prefs.h" #include "mongoc-read-concern.h" #include "mongoc-write-concern.h" BSON_BEGIN_DECLS struct _mongoc_database_t { mongoc_client_t *client; char name [128]; mongoc_read_prefs_t *read_prefs; mongoc_read_concern_t *read_concern; mongoc_write_concern_t *write_concern; }; mongoc_database_t *_mongoc_database_new (mongoc_client_t *client, const char *name, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern); mongoc_cursor_t *_mongoc_database_find_collections_legacy (mongoc_database_t *database, const bson_t *filter, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_DATABASE_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-database.c000066400000000000000000000774201264720626300207500ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-client-private.h" #include "mongoc-collection.h" #include "mongoc-collection-private.h" #include "mongoc-cursor.h" #include "mongoc-cursor-array-private.h" #include "mongoc-cursor-cursorid-private.h" #include "mongoc-cursor-transform-private.h" #include "mongoc-cursor-private.h" #include "mongoc-database.h" #include "mongoc-database-private.h" #include "mongoc-error.h" #include "mongoc-log.h" #include "mongoc-trace.h" #include "mongoc-util-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "database" /* *-------------------------------------------------------------------------- * * _mongoc_database_new -- * * Create a new instance of mongoc_database_t for @client. * * @client must stay valid for the life of the resulting * database structure. * * Returns: * A newly allocated mongoc_database_t that should be freed with * mongoc_database_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_database_t * _mongoc_database_new (mongoc_client_t *client, const char *name, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern) { mongoc_database_t *db; ENTRY; BSON_ASSERT (client); BSON_ASSERT (name); db = (mongoc_database_t *)bson_malloc0(sizeof *db); db->client = client; db->write_concern = write_concern ? mongoc_write_concern_copy(write_concern) : mongoc_write_concern_new(); db->read_concern = read_concern ? mongoc_read_concern_copy(read_concern) : mongoc_read_concern_new(); db->read_prefs = read_prefs ? mongoc_read_prefs_copy(read_prefs) : mongoc_read_prefs_new(MONGOC_READ_PRIMARY); bson_strncpy (db->name, name, sizeof db->name); RETURN(db); } /* *-------------------------------------------------------------------------- * * mongoc_database_destroy -- * * Releases resources associated with @database. * * Returns: * None. * * Side effects: * Everything. * *-------------------------------------------------------------------------- */ void mongoc_database_destroy (mongoc_database_t *database) { ENTRY; BSON_ASSERT (database); if (database->read_prefs) { mongoc_read_prefs_destroy(database->read_prefs); database->read_prefs = NULL; } if (database->read_concern) { mongoc_read_concern_destroy(database->read_concern); database->read_concern = NULL; } if (database->write_concern) { mongoc_write_concern_destroy(database->write_concern); database->write_concern = NULL; } bson_free(database); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_database_copy -- * * Returns a copy of @database that needs to be freed by calling * mongoc_database_destroy. * * Returns: * A copy of this database. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_database_t * mongoc_database_copy (mongoc_database_t *database) { ENTRY; BSON_ASSERT (database); RETURN(_mongoc_database_new(database->client, database->name, database->read_prefs, database->read_concern, database->write_concern)); } mongoc_cursor_t * mongoc_database_command (mongoc_database_t *database, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *command, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (database); BSON_ASSERT (command); if (!read_prefs) { read_prefs = database->read_prefs; } return mongoc_client_command (database->client, database->name, flags, skip, limit, batch_size, command, fields, read_prefs); } bool mongoc_database_command_simple (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error) { BSON_ASSERT (database); BSON_ASSERT (command); if (!read_prefs) { read_prefs = database->read_prefs; } return mongoc_client_command_simple (database->client, database->name, command, read_prefs, reply, error); } /* *-------------------------------------------------------------------------- * * mongoc_database_drop -- * * Requests that the MongoDB server drops @database, including all * collections and indexes associated with @database. * * Make sure this is really what you want! * * Returns: * true if @database was dropped. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ bool mongoc_database_drop (mongoc_database_t *database, bson_error_t *error) { bool ret; bson_t cmd; BSON_ASSERT (database); bson_init(&cmd); bson_append_int32(&cmd, "dropDatabase", 12, 1); ret = mongoc_database_command_simple(database, &cmd, NULL, NULL, error); bson_destroy(&cmd); return ret; } /* *-------------------------------------------------------------------------- * * mongoc_database_add_user_legacy -- * * A helper to add a user or update their password on @database. * This uses the legacy protocol by inserting into system.users. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ static bool mongoc_database_add_user_legacy (mongoc_database_t *database, const char *username, const char *password, bson_error_t *error) { mongoc_collection_t *collection; mongoc_cursor_t *cursor = NULL; const bson_t *doc; bool ret = false; bson_t query; bson_t user; char *input; char *pwd = NULL; ENTRY; BSON_ASSERT (database); BSON_ASSERT (username); BSON_ASSERT (password); /* * Users are stored in the .system.users virtual collection. */ collection = mongoc_client_get_collection(database->client, database->name, "system.users"); BSON_ASSERT(collection); /* * Hash the users password. */ input = bson_strdup_printf("%s:mongo:%s", username, password); pwd = _mongoc_hex_md5(input); bson_free(input); /* * Check to see if the user exists. If so, we will update the * password instead of inserting a new user. */ bson_init(&query); bson_append_utf8(&query, "user", 4, username, -1); cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 1, 0, &query, NULL, NULL); if (!mongoc_cursor_next(cursor, &doc)) { if (mongoc_cursor_error(cursor, error)) { GOTO (failure); } bson_init(&user); bson_append_utf8(&user, "user", 4, username, -1); bson_append_bool(&user, "readOnly", 8, false); bson_append_utf8(&user, "pwd", 3, pwd, -1); } else { bson_init(&user); bson_copy_to_excluding_noinit(doc, &user, "pwd", (char *)NULL); bson_append_utf8(&user, "pwd", 3, pwd, -1); } if (!mongoc_collection_save(collection, &user, NULL, error)) { GOTO (failure_with_user); } ret = true; failure_with_user: bson_destroy(&user); failure: if (cursor) { mongoc_cursor_destroy(cursor); } mongoc_collection_destroy(collection); bson_destroy(&query); bson_free(pwd); RETURN (ret); } bool mongoc_database_remove_user (mongoc_database_t *database, const char *username, bson_error_t *error) { mongoc_collection_t *col; bson_error_t lerror; bson_t cmd; bool ret; ENTRY; BSON_ASSERT (database); BSON_ASSERT (username); bson_init (&cmd); BSON_APPEND_UTF8 (&cmd, "dropUser", username); ret = mongoc_database_command_simple (database, &cmd, NULL, NULL, &lerror); bson_destroy (&cmd); if (!ret && (lerror.code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND)) { bson_init (&cmd); BSON_APPEND_UTF8 (&cmd, "user", username); col = mongoc_client_get_collection (database->client, database->name, "system.users"); BSON_ASSERT (col); ret = mongoc_collection_remove (col, MONGOC_REMOVE_SINGLE_REMOVE, &cmd, NULL, error); bson_destroy (&cmd); mongoc_collection_destroy (col); } else if (error) { memcpy (error, &lerror, sizeof *error); } RETURN (ret); } bool mongoc_database_remove_all_users (mongoc_database_t *database, bson_error_t *error) { mongoc_collection_t *col; bson_error_t lerror; bson_t cmd; bool ret; ENTRY; BSON_ASSERT (database); bson_init (&cmd); BSON_APPEND_INT32 (&cmd, "dropAllUsersFromDatabase", 1); ret = mongoc_database_command_simple (database, &cmd, NULL, NULL, &lerror); bson_destroy (&cmd); if (!ret && (lerror.code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND)) { bson_init (&cmd); col = mongoc_client_get_collection (database->client, database->name, "system.users"); BSON_ASSERT (col); ret = mongoc_collection_remove (col, MONGOC_REMOVE_NONE, &cmd, NULL, error); bson_destroy (&cmd); mongoc_collection_destroy (col); } else if (error) { memcpy (error, &lerror, sizeof *error); } RETURN (ret); } /** * mongoc_database_add_user: * @database: A #mongoc_database_t. * @username: A string containing the username. * @password: (allow-none): A string containing password, or NULL. * @roles: (allow-none): An optional bson_t of roles. * @custom_data: (allow-none): An optional bson_t of data to store. * @error: (out) (allow-none): A location for a bson_error_t or %NULL. * * Creates a new user with access to @database. * * Returns: None. * Side effects: None. */ bool mongoc_database_add_user (mongoc_database_t *database, const char *username, const char *password, const bson_t *roles, const bson_t *custom_data, bson_error_t *error) { bson_error_t lerror; bson_t cmd; bson_t ar; char *input; char *hashed_password; bool ret = false; ENTRY; BSON_ASSERT (database); BSON_ASSERT (username); /* * CDRIVER-232: * * Perform a (slow and tedious) round trip to mongod to determine if * we can safely call createUser. Otherwise, we will fallback and * perform legacy insertion into users collection. */ bson_init (&cmd); BSON_APPEND_UTF8 (&cmd, "usersInfo", username); ret = mongoc_database_command_simple (database, &cmd, NULL, NULL, &lerror); bson_destroy (&cmd); if (!ret && (lerror.code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND)) { ret = mongoc_database_add_user_legacy (database, username, password, error); } else if (ret || (lerror.code == 13)) { /* usersInfo succeeded or failed with auth err, we're on modern mongod */ input = bson_strdup_printf ("%s:mongo:%s", username, password); hashed_password = _mongoc_hex_md5 (input); bson_free (input); bson_init (&cmd); BSON_APPEND_UTF8 (&cmd, "createUser", username); BSON_APPEND_UTF8 (&cmd, "pwd", hashed_password); BSON_APPEND_BOOL (&cmd, "digestPassword", false); if (custom_data) { BSON_APPEND_DOCUMENT (&cmd, "customData", custom_data); } if (roles) { BSON_APPEND_ARRAY (&cmd, "roles", roles); } else { bson_append_array_begin (&cmd, "roles", 5, &ar); bson_append_array_end (&cmd, &ar); } ret = mongoc_database_command_simple (database, &cmd, NULL, NULL, error); bson_free (hashed_password); bson_destroy (&cmd); } else if (error) { memcpy (error, &lerror, sizeof *error); } RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_database_get_read_prefs -- * * Fetch the read preferences for @database. * * Returns: * A mongoc_read_prefs_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_prefs_t * mongoc_database_get_read_prefs (const mongoc_database_t *database) /* IN */ { BSON_ASSERT (database); return database->read_prefs; } /* *-------------------------------------------------------------------------- * * mongoc_database_set_read_prefs -- * * Sets the default read preferences for @database. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_database_set_read_prefs (mongoc_database_t *database, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (database); if (database->read_prefs) { mongoc_read_prefs_destroy(database->read_prefs); database->read_prefs = NULL; } if (read_prefs) { database->read_prefs = mongoc_read_prefs_copy(read_prefs); } } /* *-------------------------------------------------------------------------- * * mongoc_database_get_read_concern -- * * Fetches the read concern for @database. * * Returns: * A mongoc_read_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_concern_t * mongoc_database_get_read_concern (const mongoc_database_t *database) { BSON_ASSERT (database); return database->read_concern; } /* *-------------------------------------------------------------------------- * * mongoc_database_set_read_concern -- * * Set the default read concern for @database. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_database_set_read_concern (mongoc_database_t *database, const mongoc_read_concern_t *read_concern) { BSON_ASSERT (database); if (database->read_concern) { mongoc_read_concern_destroy (database->read_concern); database->read_concern = NULL; } if (read_concern) { database->read_concern = mongoc_read_concern_copy (read_concern); } } /* *-------------------------------------------------------------------------- * * mongoc_database_get_write_concern -- * * Fetches the write concern for @database. * * Returns: * A mongoc_write_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_write_concern_t * mongoc_database_get_write_concern (const mongoc_database_t *database) { BSON_ASSERT (database); return database->write_concern; } /* *-------------------------------------------------------------------------- * * mongoc_database_set_write_concern -- * * Set the default write concern for @database. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_database_set_write_concern (mongoc_database_t *database, const mongoc_write_concern_t *write_concern) { BSON_ASSERT (database); if (database->write_concern) { mongoc_write_concern_destroy(database->write_concern); database->write_concern = NULL; } if (write_concern) { database->write_concern = mongoc_write_concern_copy(write_concern); } } /** * mongoc_database_has_collection: * @database: (in): A #mongoc_database_t. * @name: (in): The name of the collection to check for. * @error: (out) (allow-none): A location for a #bson_error_t, or %NULL. * * Checks to see if a collection exists within the database on the MongoDB * server. * * This will return %false if their was an error communicating with the * server, or if the collection does not exist. * * If @error is provided, it will first be zeroed. Upon error, error.domain * will be set. * * Returns: %true if @name exists, otherwise %false. @error may be set. */ bool mongoc_database_has_collection (mongoc_database_t *database, const char *name, bson_error_t *error) { bson_iter_t col_iter; bool ret = false; const char *cur_name; bson_t filter = BSON_INITIALIZER; mongoc_cursor_t *cursor; const bson_t *doc; ENTRY; BSON_ASSERT (database); BSON_ASSERT (name); if (error) { memset (error, 0, sizeof *error); } BSON_APPEND_UTF8 (&filter, "name", name); cursor = mongoc_database_find_collections (database, &filter, error); if (!cursor) { return ret; } if (error && ((error->domain != 0) || (error->code != 0))) { GOTO (cleanup); } while (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init (&col_iter, doc) && bson_iter_find (&col_iter, "name") && BSON_ITER_HOLDS_UTF8 (&col_iter) && (cur_name = bson_iter_utf8 (&col_iter, NULL))) { if (!strcmp (cur_name, name)) { ret = true; GOTO (cleanup); } } } cleanup: mongoc_cursor_destroy (cursor); RETURN (ret); } typedef struct { const char *dbname; size_t dbname_len; const char *name; } mongoc_database_find_collections_legacy_ctx_t; static mongoc_cursor_transform_mode_t _mongoc_database_find_collections_legacy_filter (const bson_t *bson, void *ctx_) { bson_iter_t iter; mongoc_database_find_collections_legacy_ctx_t *ctx; ctx = (mongoc_database_find_collections_legacy_ctx_t *)ctx_; if (bson_iter_init_find (&iter, bson, "name") && BSON_ITER_HOLDS_UTF8 (&iter) && (ctx->name = bson_iter_utf8 (&iter, NULL)) && !strchr (ctx->name, '$') && (0 == strncmp (ctx->name, ctx->dbname, ctx->dbname_len))) { return MONGO_CURSOR_TRANSFORM_MUTATE; } else { return MONGO_CURSOR_TRANSFORM_DROP; } } static void _mongoc_database_find_collections_legacy_mutate (const bson_t *bson, bson_t *out, void *ctx_) { mongoc_database_find_collections_legacy_ctx_t *ctx; ctx = (mongoc_database_find_collections_legacy_ctx_t *)ctx_; bson_copy_to_excluding_noinit (bson, out, "name", NULL); BSON_APPEND_UTF8 (out, "name", ctx->name + (ctx->dbname_len + 1)); /* +1 for the '.' */ } /* Uses old way of querying system.namespaces. */ mongoc_cursor_t * _mongoc_database_find_collections_legacy (mongoc_database_t *database, const bson_t *filter, bson_error_t *error) { mongoc_collection_t *col; mongoc_cursor_t *cursor = NULL; mongoc_read_prefs_t *read_prefs; uint32_t dbname_len; bson_t legacy_filter; bson_iter_t iter; const char *col_filter; bson_t q = BSON_INITIALIZER; mongoc_database_find_collections_legacy_ctx_t *ctx; BSON_ASSERT (database); col = mongoc_client_get_collection (database->client, database->name, "system.namespaces"); BSON_ASSERT (col); dbname_len = (uint32_t)strlen (database->name); ctx = (mongoc_database_find_collections_legacy_ctx_t *)bson_malloc (sizeof (*ctx)); ctx->dbname = database->name; ctx->dbname_len = dbname_len; /* Filtering on name needs to be handled differently for old servers. */ if (filter && bson_iter_init_find (&iter, filter, "name")) { bson_string_t *buf; /* on legacy servers, this must be a string (i.e. not a regex) */ if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_NAMESPACE, MONGOC_ERROR_NAMESPACE_INVALID_FILTER_TYPE, "On legacy servers, a filter on name can only be a string."); bson_free (ctx); goto cleanup_filter; } BSON_ASSERT (BSON_ITER_HOLDS_UTF8 (&iter)); col_filter = bson_iter_utf8 (&iter, NULL); bson_init (&legacy_filter); bson_copy_to_excluding_noinit (filter, &legacy_filter, "name", NULL); /* We must db-qualify filters on name. */ buf = bson_string_new (database->name); bson_string_append_c (buf, '.'); bson_string_append (buf, col_filter); BSON_APPEND_UTF8 (&legacy_filter, "name", buf->str); bson_string_free (buf, true); filter = &legacy_filter; } read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); cursor = mongoc_collection_find (col, MONGOC_QUERY_NONE, 0, 0, 0, filter ? filter : &q, NULL, read_prefs); _mongoc_cursor_transform_init ( cursor, _mongoc_database_find_collections_legacy_filter, _mongoc_database_find_collections_legacy_mutate, &bson_free, ctx); mongoc_read_prefs_destroy (read_prefs); cleanup_filter: mongoc_collection_destroy (col); return cursor; } mongoc_cursor_t * mongoc_database_find_collections (mongoc_database_t *database, const bson_t *filter, bson_error_t *error) { mongoc_cursor_t *cursor; mongoc_read_prefs_t *read_prefs; bson_t cmd = BSON_INITIALIZER; bson_t child; bson_error_t lerror; BSON_ASSERT (database); BSON_APPEND_INT32 (&cmd, "listCollections", 1); if (filter) { BSON_APPEND_DOCUMENT (&cmd, "filter", filter); BSON_APPEND_DOCUMENT_BEGIN (&cmd, "cursor", &child); bson_append_document_end (&cmd, &child); } read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); cursor = _mongoc_cursor_new (database->client, database->name, MONGOC_QUERY_SLAVE_OK, 0, 0, 0, true, NULL, NULL, NULL, NULL); _mongoc_cursor_cursorid_init (cursor, &cmd); if (_mongoc_cursor_cursorid_prime (cursor)) { /* intentionally empty */ } else { if (mongoc_cursor_error (cursor, &lerror)) { if (lerror.code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND) { /* We are talking to a server that doesn' support listCollections. */ /* clear out the error. */ memset (&lerror, 0, sizeof lerror); /* try again with using system.namespaces */ mongoc_cursor_destroy (cursor); cursor = _mongoc_database_find_collections_legacy ( database, filter, error); } else if (error) { memcpy (error, &lerror, sizeof *error); } } } bson_destroy (&cmd); mongoc_read_prefs_destroy (read_prefs); return cursor; } char ** mongoc_database_get_collection_names (mongoc_database_t *database, bson_error_t *error) { bson_iter_t col; const char *name; char *namecopy; mongoc_array_t strv_buf; mongoc_cursor_t *cursor; const bson_t *doc; char **ret; BSON_ASSERT (database); cursor = mongoc_database_find_collections (database, NULL, error); if (!cursor) { return NULL; } _mongoc_array_init (&strv_buf, sizeof (char *)); while (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init (&col, doc) && bson_iter_find (&col, "name") && BSON_ITER_HOLDS_UTF8 (&col) && (name = bson_iter_utf8 (&col, NULL))) { namecopy = bson_strdup (name); _mongoc_array_append_val (&strv_buf, namecopy); } } /* append a null pointer for the last value. also handles the case * of no values. */ namecopy = NULL; _mongoc_array_append_val (&strv_buf, namecopy); if (mongoc_cursor_error (cursor, error)) { _mongoc_array_destroy (&strv_buf); ret = NULL; } else { ret = (char **)strv_buf.data; } mongoc_cursor_destroy (cursor); return ret; } mongoc_collection_t * mongoc_database_create_collection (mongoc_database_t *database, const char *name, const bson_t *options, bson_error_t *error) { mongoc_collection_t *collection = NULL; bson_iter_t iter; bson_t cmd; bool capped = false; BSON_ASSERT (database); BSON_ASSERT (name); if (strchr (name, '$')) { bson_set_error (error, MONGOC_ERROR_NAMESPACE, MONGOC_ERROR_NAMESPACE_INVALID, "The namespace \"%s\" is invalid.", name); return NULL; } if (options) { if (bson_iter_init_find (&iter, options, "capped")) { if (!BSON_ITER_HOLDS_BOOL (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The argument \"capped\" must be a boolean."); return NULL; } capped = bson_iter_bool (&iter); } if (bson_iter_init_find (&iter, options, "autoIndexId") && !BSON_ITER_HOLDS_BOOL (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The argument \"autoIndexId\" must be a boolean."); return NULL; } if (bson_iter_init_find (&iter, options, "size")) { if (!BSON_ITER_HOLDS_INT32 (&iter) && !BSON_ITER_HOLDS_INT64 (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The argument \"size\" must be an integer."); return NULL; } if (!capped) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"size\" parameter requires {\"capped\": true}"); return NULL; } } if (bson_iter_init_find (&iter, options, "max")) { if (!BSON_ITER_HOLDS_INT32 (&iter) && !BSON_ITER_HOLDS_INT64 (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The argument \"max\" must be an integer."); return NULL; } if (!capped) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"max\" parameter requires {\"capped\": true}"); return NULL; } } if (bson_iter_init_find (&iter, options, "storage")) { if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"storage\" parameter must be a document"); return NULL; } if (bson_iter_find (&iter, "wiredtiger")) { if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"wiredtiger\" option must take a document argument with a \"configString\" field"); return NULL; } if (bson_iter_find (&iter, "configString")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"configString\" parameter must be a string"); return NULL; } } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"wiredtiger\" option must take a document argument with a \"configString\" field"); return NULL; } } } } bson_init (&cmd); BSON_APPEND_UTF8 (&cmd, "create", name); if (options) { if (!bson_iter_init (&iter, options)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The argument \"options\" is corrupt or invalid."); bson_destroy (&cmd); return NULL; } while (bson_iter_next (&iter)) { if (!bson_append_iter (&cmd, bson_iter_key (&iter), -1, &iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Failed to append \"options\" to create command."); bson_destroy (&cmd); return NULL; } } } if (mongoc_database_command_simple (database, &cmd, NULL, NULL, error)) { collection = _mongoc_collection_new (database->client, database->name, name, database->read_prefs, database->read_concern, database->write_concern); } bson_destroy (&cmd); return collection; } mongoc_collection_t * mongoc_database_get_collection (mongoc_database_t *database, const char *collection) { BSON_ASSERT (database); BSON_ASSERT (collection); return mongoc_client_get_collection (database->client, database->name, collection); } const char * mongoc_database_get_name (mongoc_database_t *database) { BSON_ASSERT (database); return database->name; } libmongoc-1.3.1/src/mongoc/mongoc-database.h000066400000000000000000000150041264720626300207430ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_DATABASE_H #define MONGOC_DATABASE_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-cursor.h" #include "mongoc-flags.h" #include "mongoc-read-prefs.h" #include "mongoc-read-concern.h" #include "mongoc-write-concern.h" BSON_BEGIN_DECLS typedef struct _mongoc_database_t mongoc_database_t; const char *mongoc_database_get_name (mongoc_database_t *database); bool mongoc_database_remove_user (mongoc_database_t *database, const char *username, bson_error_t *error); bool mongoc_database_remove_all_users (mongoc_database_t *database, bson_error_t *error); bool mongoc_database_add_user (mongoc_database_t *database, const char *username, const char *password, const bson_t *roles, const bson_t *custom_data, bson_error_t *error); void mongoc_database_destroy (mongoc_database_t *database); mongoc_database_t *mongoc_database_copy (mongoc_database_t *database); mongoc_cursor_t *mongoc_database_command (mongoc_database_t *database, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *command, const bson_t *fields, const mongoc_read_prefs_t *read_prefs); bool mongoc_database_command_simple (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error); bool mongoc_database_drop (mongoc_database_t *database, bson_error_t *error); bool mongoc_database_has_collection (mongoc_database_t *database, const char *name, bson_error_t *error); mongoc_collection_t *mongoc_database_create_collection (mongoc_database_t *database, const char *name, const bson_t *options, bson_error_t *error); const mongoc_read_prefs_t *mongoc_database_get_read_prefs (const mongoc_database_t *database); void mongoc_database_set_read_prefs (mongoc_database_t *database, const mongoc_read_prefs_t *read_prefs); const mongoc_write_concern_t *mongoc_database_get_write_concern (const mongoc_database_t *database); void mongoc_database_set_write_concern (mongoc_database_t *database, const mongoc_write_concern_t *write_concern); const mongoc_read_concern_t *mongoc_database_get_read_concern (const mongoc_database_t *database); void mongoc_database_set_read_concern (mongoc_database_t *database, const mongoc_read_concern_t *read_concern); mongoc_cursor_t *mongoc_database_find_collections (mongoc_database_t *database, const bson_t *filter, bson_error_t *error); char **mongoc_database_get_collection_names (mongoc_database_t *database, bson_error_t *error); mongoc_collection_t *mongoc_database_get_collection (mongoc_database_t *database, const char *name); BSON_END_DECLS #endif /* MONGOC_DATABASE_H */ libmongoc-1.3.1/src/mongoc/mongoc-errno-private.h000066400000000000000000000026771264720626300220100ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_ERRNO_PRIVATE_H #define MONGOC_ERRNO_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include #ifdef _WIN32 # include # include #endif BSON_BEGIN_DECLS #if defined(_WIN32) # define MONGOC_ERRNO_IS_AGAIN(errno) ((errno == EAGAIN) || (errno == WSAEWOULDBLOCK) || (errno == WSAEINPROGRESS)) #elif defined(__sun) /* for some reason, accept() returns -1 and errno of 0 */ # define MONGOC_ERRNO_IS_AGAIN(errno) ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == 0)) #else # define MONGOC_ERRNO_IS_AGAIN(errno) ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS)) #endif BSON_END_DECLS #endif /* MONGOC_ERRNO_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-error.h000066400000000000000000000054141264720626300203340ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_ERRORS_H #define MONGOC_ERRORS_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef enum { MONGOC_ERROR_CLIENT = 1, MONGOC_ERROR_STREAM, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_CURSOR, MONGOC_ERROR_QUERY, MONGOC_ERROR_INSERT, MONGOC_ERROR_SASL, MONGOC_ERROR_BSON, MONGOC_ERROR_MATCHER, MONGOC_ERROR_NAMESPACE, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COLLECTION, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_WRITE_CONCERN, } mongoc_error_domain_t; typedef enum { MONGOC_ERROR_STREAM_INVALID_TYPE = 1, MONGOC_ERROR_STREAM_INVALID_STATE, MONGOC_ERROR_STREAM_NAME_RESOLUTION, MONGOC_ERROR_STREAM_SOCKET, MONGOC_ERROR_STREAM_CONNECT, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, MONGOC_ERROR_CLIENT_NOT_READY, MONGOC_ERROR_CLIENT_TOO_BIG, MONGOC_ERROR_CLIENT_TOO_SMALL, MONGOC_ERROR_CLIENT_GETNONCE, MONGOC_ERROR_CLIENT_AUTHENTICATE, MONGOC_ERROR_CLIENT_NO_ACCEPTABLE_PEER, MONGOC_ERROR_CLIENT_IN_EXHAUST, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, MONGOC_ERROR_CURSOR_INVALID_CURSOR, MONGOC_ERROR_QUERY_FAILURE, MONGOC_ERROR_BSON_INVALID, MONGOC_ERROR_MATCHER_INVALID, MONGOC_ERROR_NAMESPACE_INVALID, MONGOC_ERROR_NAMESPACE_INVALID_FILTER_TYPE, MONGOC_ERROR_COMMAND_INVALID_ARG, MONGOC_ERROR_COLLECTION_INSERT_FAILED, MONGOC_ERROR_COLLECTION_UPDATE_FAILED, MONGOC_ERROR_COLLECTION_DELETE_FAILED, MONGOC_ERROR_COLLECTION_DOES_NOT_EXIST = 26, MONGOC_ERROR_GRIDFS_INVALID_FILENAME, MONGOC_ERROR_SCRAM_NOT_DONE, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND = 59, MONGOC_ERROR_QUERY_NOT_TAILABLE = 13051, MONGOC_ERROR_SERVER_SELECTION_BAD_WIRE_VERSION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, MONGOC_ERROR_SERVER_SELECTION_INVALID_ID, MONGOC_ERROR_GRIDFS_CHUNK_MISSING, /* Dup with query failure. */ MONGOC_ERROR_PROTOCOL_ERROR = 17, MONGOC_ERROR_WRITE_CONCERN_ERROR = 64, } mongoc_error_code_t; BSON_END_DECLS #endif /* MONGOC_ERRORS_H */ libmongoc-1.3.1/src/mongoc/mongoc-find-and-modify-private.h000066400000000000000000000023731264720626300236210ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_FIND_AND_MODIFY_PRIVATE_H #define MONGOC_FIND_AND_MODIFY_PRIVATE_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-write-command-private.h" BSON_BEGIN_DECLS struct _mongoc_find_and_modify_opts_t { bson_t *sort; bson_t *update; bson_t *fields; mongoc_find_and_modify_flags_t flags; mongoc_write_bypass_document_validation_t bypass_document_validation; }; BSON_END_DECLS #endif /* MONGOC_FIND_AND_MODIFY_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-find-and-modify.c000066400000000000000000000064411264720626300221440ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-write-concern.h" #include "mongoc-write-concern-private.h" #include "mongoc-find-and-modify.h" #include "mongoc-find-and-modify-private.h" #include "mongoc-util-private.h" /** * mongoc_find_and_modify_new: * * Create a new mongoc_find_and_modify_t. * * Returns: A newly allocated mongoc_find_and_modify_t. This should be freed * with mongoc_find_and_modify_destroy(). */ mongoc_find_and_modify_opts_t* mongoc_find_and_modify_opts_new (void) { mongoc_find_and_modify_opts_t *opts = NULL; opts = (mongoc_find_and_modify_opts_t *)bson_malloc0 (sizeof *opts); opts->bypass_document_validation = MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT; return opts; } bool mongoc_find_and_modify_opts_set_sort (mongoc_find_and_modify_opts_t *opts, const bson_t *sort) { BSON_ASSERT (opts); if (sort) { _mongoc_bson_destroy_if_set (opts->sort); opts->sort = bson_copy (sort); return true; } return false; } bool mongoc_find_and_modify_opts_set_update (mongoc_find_and_modify_opts_t *opts, const bson_t *update) { BSON_ASSERT (opts); if (update) { _mongoc_bson_destroy_if_set (opts->update); opts->update = bson_copy (update); return true; } return false; } bool mongoc_find_and_modify_opts_set_fields (mongoc_find_and_modify_opts_t *opts, const bson_t *fields) { BSON_ASSERT (opts); if (fields) { _mongoc_bson_destroy_if_set (opts->fields); opts->fields = bson_copy (fields); return true; } return false; } bool mongoc_find_and_modify_opts_set_flags (mongoc_find_and_modify_opts_t *opts, const mongoc_find_and_modify_flags_t flags) { BSON_ASSERT (opts); opts->flags = flags; return true; } bool mongoc_find_and_modify_opts_set_bypass_document_validation (mongoc_find_and_modify_opts_t *opts, bool bypass) { BSON_ASSERT (opts); opts->bypass_document_validation = bypass ? MONGOC_BYPASS_DOCUMENT_VALIDATION_TRUE : MONGOC_BYPASS_DOCUMENT_VALIDATION_FALSE; return true; } /** * mongoc_find_and_modify_opts_destroy: * @opts: A mongoc_find_and_modify_opts_t. * * Releases a mongoc_find_and_modify_opts_t and all associated memory. */ void mongoc_find_and_modify_opts_destroy (mongoc_find_and_modify_opts_t *opts) { if (opts) { _mongoc_bson_destroy_if_set (opts->sort); _mongoc_bson_destroy_if_set (opts->update); _mongoc_bson_destroy_if_set (opts->fields); bson_free (opts); } } libmongoc-1.3.1/src/mongoc/mongoc-find-and-modify.h000066400000000000000000000044111264720626300221440ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_FIND_AND_MODIFY_H #define MONGOC_FIND_AND_MODIFY_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef enum { MONGOC_FIND_AND_MODIFY_NONE = 0, MONGOC_FIND_AND_MODIFY_REMOVE = 1 << 0, MONGOC_FIND_AND_MODIFY_UPSERT = 1 << 1, MONGOC_FIND_AND_MODIFY_RETURN_NEW = 1 << 2, } mongoc_find_and_modify_flags_t; typedef struct _mongoc_find_and_modify_opts_t mongoc_find_and_modify_opts_t ; mongoc_find_and_modify_opts_t* mongoc_find_and_modify_opts_new (void); bool mongoc_find_and_modify_opts_set_sort (mongoc_find_and_modify_opts_t *opts, const bson_t *sort); bool mongoc_find_and_modify_opts_set_update (mongoc_find_and_modify_opts_t *opts, const bson_t *update); bool mongoc_find_and_modify_opts_set_fields (mongoc_find_and_modify_opts_t *opts, const bson_t *fields); bool mongoc_find_and_modify_opts_set_flags (mongoc_find_and_modify_opts_t *opts, const mongoc_find_and_modify_flags_t flags); bool mongoc_find_and_modify_opts_set_bypass_document_validation (mongoc_find_and_modify_opts_t *opts, bool bypass); void mongoc_find_and_modify_opts_destroy (mongoc_find_and_modify_opts_t *opts); BSON_END_DECLS #endif /* MONGOC_FIND_AND_MODIFY_H */ libmongoc-1.3.1/src/mongoc/mongoc-flags.h000066400000000000000000000112641264720626300202770ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_FLAGS_H #define MONGOC_FLAGS_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS /** * mongoc_delete_flags_t: * @MONGOC_DELETE_NONE: Specify no delete flags. * @MONGOC_DELETE_SINGLE_REMOVE: Only remove the first document matching the * document selector. * * This type is only for use with deprecated functions and should not be * used in new code. Use mongoc_remove_flags_t instead. * * #mongoc_delete_flags_t are used when performing a delete operation. */ typedef enum { MONGOC_DELETE_NONE = 0, MONGOC_DELETE_SINGLE_REMOVE = 1 << 0, } mongoc_delete_flags_t; /** * mongoc_remove_flags_t: * @MONGOC_REMOVE_NONE: Specify no delete flags. * @MONGOC_REMOVE_SINGLE_REMOVE: Only remove the first document matching the * document selector. * * #mongoc_remove_flags_t are used when performing a remove operation. */ typedef enum { MONGOC_REMOVE_NONE = 0, MONGOC_REMOVE_SINGLE_REMOVE = 1 << 0, } mongoc_remove_flags_t; /** * mongoc_insert_flags_t: * @MONGOC_INSERT_NONE: Specify no insert flags. * @MONGOC_INSERT_CONTINUE_ON_ERROR: Continue inserting documents from * the insertion set even if one fails. * * #mongoc_insert_flags_t are used when performing an insert operation. */ typedef enum { MONGOC_INSERT_NONE = 0, MONGOC_INSERT_CONTINUE_ON_ERROR = 1 << 0, } mongoc_insert_flags_t; #define MONGOC_INSERT_NO_VALIDATE (1U << 31) /** * mongoc_query_flags_t: * @MONGOC_QUERY_NONE: No query flags supplied. * @MONGOC_QUERY_TAILABLE_CURSOR: Cursor will not be closed when the last * data is retrieved. You can resume this cursor later. * @MONGOC_QUERY_SLAVE_OK: Allow query of replica slave. * @MONGOC_QUERY_OPLOG_REPLAY: Used internally by Mongo. * @MONGOC_QUERY_NO_CURSOR_TIMEOUT: The server normally times out idle * cursors after an inactivity period (10 minutes). This prevents that. * @MONGOC_QUERY_AWAIT_DATA: Use with %MONGOC_QUERY_TAILABLE_CURSOR. Block * rather than returning no data. After a period, time out. * @MONGOC_QUERY_EXHAUST: Stream the data down full blast in multiple * "more" packages. Faster when you are pulling a lot of data and * know you want to pull it all down. * @MONGOC_QUERY_PARTIAL: Get partial results from mongos if some shards * are down (instead of throwing an error). * * #mongoc_query_flags_t is used for querying a Mongo instance. */ typedef enum { MONGOC_QUERY_NONE = 0, MONGOC_QUERY_TAILABLE_CURSOR = 1 << 1, MONGOC_QUERY_SLAVE_OK = 1 << 2, MONGOC_QUERY_OPLOG_REPLAY = 1 << 3, MONGOC_QUERY_NO_CURSOR_TIMEOUT = 1 << 4, MONGOC_QUERY_AWAIT_DATA = 1 << 5, MONGOC_QUERY_EXHAUST = 1 << 6, MONGOC_QUERY_PARTIAL = 1 << 7, } mongoc_query_flags_t; /** * mongoc_reply_flags_t: * @MONGOC_REPLY_NONE: No flags set. * @MONGOC_REPLY_CURSOR_NOT_FOUND: Cursor was not found. * @MONGOC_REPLY_QUERY_FAILURE: Query failed, error document provided. * @MONGOC_REPLY_SHARD_CONFIG_STALE: Shard configuration is stale. * @MONGOC_REPLY_AWAIT_CAPABLE: Wait for data to be returned until timeout * has passed. Used with %MONGOC_QUERY_TAILABLE_CURSOR. * * #mongoc_reply_flags_t contains flags supplied by the Mongo server in reply * to a request. */ typedef enum { MONGOC_REPLY_NONE = 0, MONGOC_REPLY_CURSOR_NOT_FOUND = 1 << 0, MONGOC_REPLY_QUERY_FAILURE = 1 << 1, MONGOC_REPLY_SHARD_CONFIG_STALE = 1 << 2, MONGOC_REPLY_AWAIT_CAPABLE = 1 << 3, } mongoc_reply_flags_t; /** * mongoc_update_flags_t: * @MONGOC_UPDATE_NONE: No update flags specified. * @MONGOC_UPDATE_UPSERT: Perform an upsert. * @MONGOC_UPDATE_MULTI_UPDATE: Continue updating after first match. * * #mongoc_update_flags_t is used when updating documents found in Mongo. */ typedef enum { MONGOC_UPDATE_NONE = 0, MONGOC_UPDATE_UPSERT = 1 << 0, MONGOC_UPDATE_MULTI_UPDATE = 1 << 1, } mongoc_update_flags_t; #define MONGOC_UPDATE_NO_VALIDATE (1U << 31) BSON_END_DECLS #endif /* MONGOC_FLAGS_H */ libmongoc-1.3.1/src/mongoc/mongoc-gridfs-file-list-private.h000066400000000000000000000025311264720626300240140ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_GRIDFS_FILE_LIST_PRIVATE_H #define MONGOC_GRIDFS_FILE_LIST_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-gridfs.h" #include "mongoc-gridfs-file.h" #include "mongoc-cursor.h" BSON_BEGIN_DECLS struct _mongoc_gridfs_file_list_t { mongoc_gridfs_t *gridfs; mongoc_cursor_t *cursor; bson_error_t error; }; mongoc_gridfs_file_list_t *_mongoc_gridfs_file_list_new (mongoc_gridfs_t *gridfs, const bson_t *query, uint32_t limit); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_LIST_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-gridfs-file-list.c000066400000000000000000000042351264720626300223420ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-cursor.h" #include "mongoc-cursor-private.h" #include "mongoc-gridfs.h" #include "mongoc-gridfs-private.h" #include "mongoc-gridfs-file.h" #include "mongoc-gridfs-file-private.h" #include "mongoc-gridfs-file-list.h" #include "mongoc-gridfs-file-list-private.h" #include "mongoc-trace.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs_file_list" mongoc_gridfs_file_list_t * _mongoc_gridfs_file_list_new (mongoc_gridfs_t *gridfs, const bson_t *query, uint32_t limit) { mongoc_gridfs_file_list_t *list; mongoc_cursor_t *cursor; cursor = mongoc_collection_find (gridfs->files, MONGOC_QUERY_NONE, 0, limit, 0, query, NULL, NULL); BSON_ASSERT (cursor); list = (mongoc_gridfs_file_list_t *)bson_malloc0 (sizeof *list); list->cursor = cursor; list->gridfs = gridfs; return list; } mongoc_gridfs_file_t * mongoc_gridfs_file_list_next (mongoc_gridfs_file_list_t *list) { const bson_t *bson; BSON_ASSERT (list); if (mongoc_cursor_next (list->cursor, &bson)) { return _mongoc_gridfs_file_new_from_bson (list->gridfs, bson); } else { return NULL; } } bool mongoc_gridfs_file_list_error (mongoc_gridfs_file_list_t *list, bson_error_t *error) { return mongoc_cursor_error(list->cursor, error); } void mongoc_gridfs_file_list_destroy (mongoc_gridfs_file_list_t *list) { BSON_ASSERT (list); mongoc_cursor_destroy (list->cursor); bson_free (list); } libmongoc-1.3.1/src/mongoc/mongoc-gridfs-file-list.h000066400000000000000000000024771264720626300223550ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_GRIDFS_FILE_LIST_H #define MONGOC_GRIDFS_FILE_LIST_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-gridfs-file.h" BSON_BEGIN_DECLS typedef struct _mongoc_gridfs_file_list_t mongoc_gridfs_file_list_t; mongoc_gridfs_file_t *mongoc_gridfs_file_list_next (mongoc_gridfs_file_list_t *list); void mongoc_gridfs_file_list_destroy (mongoc_gridfs_file_list_t *list); bool mongoc_gridfs_file_list_error (mongoc_gridfs_file_list_t *list, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_LIST_H */ libmongoc-1.3.1/src/mongoc/mongoc-gridfs-file-page-private.h000066400000000000000000000054271264720626300237640ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_GRIDFS_FILE_PAGE_PRIVATE_H #define MONGOC_GRIDFS_FILE_PAGE_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-gridfs-file.h" BSON_BEGIN_DECLS struct _mongoc_gridfs_file_page_t { const uint8_t *read_buf; uint8_t *buf; uint32_t len; uint32_t chunk_size; uint32_t offset; }; mongoc_gridfs_file_page_t *_mongoc_gridfs_file_page_new (const uint8_t *data, uint32_t len, uint32_t chunk_size); void _mongoc_gridfs_file_page_destroy (mongoc_gridfs_file_page_t *page); bool _mongoc_gridfs_file_page_seek (mongoc_gridfs_file_page_t *page, uint32_t offset); int32_t _mongoc_gridfs_file_page_read (mongoc_gridfs_file_page_t *page, void *dst, uint32_t len); int32_t _mongoc_gridfs_file_page_write (mongoc_gridfs_file_page_t *page, const void *src, uint32_t len); bool _mongoc_gridfs_file_page_memset0 (mongoc_gridfs_file_page_t *page, uint32_t len); uint32_t _mongoc_gridfs_file_page_tell (mongoc_gridfs_file_page_t *page); const uint8_t *_mongoc_gridfs_file_page_get_data (mongoc_gridfs_file_page_t *page); uint32_t _mongoc_gridfs_file_page_get_len (mongoc_gridfs_file_page_t *page); bool _mongoc_gridfs_file_page_is_dirty (mongoc_gridfs_file_page_t *page); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_PAGE_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-gridfs-file-page.c000066400000000000000000000121321264720626300222760ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs_file_page" #include "mongoc-gridfs-file-page.h" #include "mongoc-gridfs-file-page-private.h" #include "mongoc-trace.h" /** create a new page from a buffer * * The buffer should stick around for the life of the page */ mongoc_gridfs_file_page_t * _mongoc_gridfs_file_page_new (const uint8_t *data, uint32_t len, uint32_t chunk_size) { mongoc_gridfs_file_page_t *page; ENTRY; BSON_ASSERT (data); BSON_ASSERT (len <= chunk_size); page = (mongoc_gridfs_file_page_t *)bson_malloc0 (sizeof *page); page->chunk_size = chunk_size; page->read_buf = data; page->len = len; RETURN (page); } bool _mongoc_gridfs_file_page_seek (mongoc_gridfs_file_page_t *page, uint32_t offset) { ENTRY; BSON_ASSERT (page); page->offset = offset; RETURN (1); } int32_t _mongoc_gridfs_file_page_read (mongoc_gridfs_file_page_t *page, void *dst, uint32_t len) { int bytes_read; const uint8_t *src; ENTRY; BSON_ASSERT (page); BSON_ASSERT (dst); bytes_read = BSON_MIN (len, page->len - page->offset); src = page->read_buf ? page->read_buf : page->buf; memcpy (dst, src + page->offset, bytes_read); page->offset += bytes_read; RETURN (bytes_read); } /** * _mongoc_gridfs_file_page_write: * * Write to a page. * * Writes are copy-on-write with regards to the buffer that was passed to the * mongoc_gridfs_file_page_t during construction. In other words, the first * write allocates a large enough buffer for file->chunk_size, which becomes * authoritative from then on. * * A write of zero bytes will trigger the copy-on-write mechanism. */ int32_t _mongoc_gridfs_file_page_write (mongoc_gridfs_file_page_t *page, const void *src, uint32_t len) { int bytes_written; ENTRY; BSON_ASSERT (page); BSON_ASSERT (src); bytes_written = BSON_MIN (len, page->chunk_size - page->offset); if (!page->buf) { page->buf = (uint8_t *) bson_malloc (page->chunk_size); memcpy (page->buf, page->read_buf, BSON_MIN (page->chunk_size, page->len)); } /* Copy bytes and adjust the page position */ memcpy (page->buf + page->offset, src, bytes_written); page->offset += bytes_written; page->len = BSON_MAX (page->offset, page->len); /* Don't use the old read buffer, which is no longer current */ page->read_buf = page->buf; RETURN (bytes_written); } /** * _mongoc_gridfs_file_page_memset0: * * Write zeros to a page, starting from the page's current position. Up to * `len` bytes will be set to zero or until the page is full, whichever * comes first. * * Like _mongoc_gridfs_file_page_write, operations are copy-on-write with * regards to the page buffer. * * Returns: * True on success; false otherwise. */ bool _mongoc_gridfs_file_page_memset0 (mongoc_gridfs_file_page_t *page, uint32_t len) { int32_t bytes_set; ENTRY; BSON_ASSERT (page); bytes_set = BSON_MIN (page->chunk_size - page->offset, len); if (!page->buf) { page->buf = (uint8_t *)bson_malloc0 (page->chunk_size); memcpy (page->buf, page->read_buf, BSON_MIN (page->chunk_size, page->len)); } /* Set bytes and adjust the page position */ memset (page->buf + page->offset, '\0', bytes_set); page->offset += bytes_set; page->len = BSON_MAX (page->offset, page->len); /* Don't use the old read buffer, which is no longer current */ page->read_buf = page->buf; RETURN (true); } const uint8_t * _mongoc_gridfs_file_page_get_data (mongoc_gridfs_file_page_t *page) { ENTRY; BSON_ASSERT (page); RETURN (page->buf ? page->buf : page->read_buf); } uint32_t _mongoc_gridfs_file_page_get_len (mongoc_gridfs_file_page_t *page) { ENTRY; BSON_ASSERT (page); RETURN (page->len); } uint32_t _mongoc_gridfs_file_page_tell (mongoc_gridfs_file_page_t *page) { ENTRY; BSON_ASSERT (page); RETURN (page->offset); } bool _mongoc_gridfs_file_page_is_dirty (mongoc_gridfs_file_page_t *page) { ENTRY; BSON_ASSERT (page); RETURN (page->buf ? 1 : 0); } void _mongoc_gridfs_file_page_destroy (mongoc_gridfs_file_page_t *page) { ENTRY; if (page->buf) { bson_free (page->buf); } bson_free (page); EXIT; } libmongoc-1.3.1/src/mongoc/mongoc-gridfs-file-page.h000066400000000000000000000020311264720626300223000ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_GRIDFS_FILE_PAGE_H #define MONGOC_GRIDFS_FILE_PAGE_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-stream.h" #include "mongoc-gridfs-file.h" #include "mongoc-gridfs-file-list.h" BSON_BEGIN_DECLS typedef struct _mongoc_gridfs_file_page_t mongoc_gridfs_file_page_t; BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_PAGE_H */ libmongoc-1.3.1/src/mongoc/mongoc-gridfs-file-private.h000066400000000000000000000045121264720626300230440ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_GRIDFS_FILE_PRIVATE_H #define MONGOC_GRIDFS_FILE_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-gridfs.h" #include "mongoc-gridfs-file.h" #include "mongoc-gridfs-file-page.h" #include "mongoc-cursor.h" BSON_BEGIN_DECLS struct _mongoc_gridfs_file_t { mongoc_gridfs_t *gridfs; bson_t bson; mongoc_gridfs_file_page_t *page; uint64_t pos; int32_t n; bson_error_t error; mongoc_cursor_t *cursor; uint32_t cursor_range[2]; /* current chunk, # of chunks */ bool is_dirty; bson_value_t files_id; int64_t length; int32_t chunk_size; int64_t upload_date; char *md5; char *filename; char *content_type; bson_t aliases; bson_t metadata; const char *bson_md5; const char *bson_filename; const char *bson_content_type; bson_t bson_aliases; bson_t bson_metadata; }; mongoc_gridfs_file_t *_mongoc_gridfs_file_new_from_bson (mongoc_gridfs_t *gridfs, const bson_t *data); mongoc_gridfs_file_t *_mongoc_gridfs_file_new (mongoc_gridfs_t *gridfs, mongoc_gridfs_file_opt_t *opt); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-gridfs-file.c000066400000000000000000000640441264720626300213750ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs_file" #include #include #include #include "mongoc-cursor.h" #include "mongoc-cursor-private.h" #include "mongoc-collection.h" #include "mongoc-gridfs.h" #include "mongoc-gridfs-private.h" #include "mongoc-gridfs-file.h" #include "mongoc-gridfs-file-private.h" #include "mongoc-gridfs-file-page.h" #include "mongoc-gridfs-file-page-private.h" #include "mongoc-iovec.h" #include "mongoc-trace.h" #include "mongoc-error.h" static bool _mongoc_gridfs_file_refresh_page (mongoc_gridfs_file_t *file); static bool _mongoc_gridfs_file_flush_page (mongoc_gridfs_file_t *file); static ssize_t _mongoc_gridfs_file_extend (mongoc_gridfs_file_t *file); /***************************************************************** * Magic accessor generation * * We need some accessors to get and set properties on files, to handle memory * ownership and to determine dirtiness. These macros produce the getters and * setters we need *****************************************************************/ #define MONGOC_GRIDFS_FILE_STR_ACCESSOR(name) \ const char * \ mongoc_gridfs_file_get_##name (mongoc_gridfs_file_t * file) \ { \ return file->name ? file->name : file->bson_##name; \ } \ void \ mongoc_gridfs_file_set_##name (mongoc_gridfs_file_t * file, \ const char *str) \ { \ if (file->name) { \ bson_free (file->name); \ } \ file->name = bson_strdup (str); \ file->is_dirty = 1; \ } #define MONGOC_GRIDFS_FILE_BSON_ACCESSOR(name) \ const bson_t * \ mongoc_gridfs_file_get_##name (mongoc_gridfs_file_t * file) \ { \ if (file->name.len) { \ return &file->name; \ } else if (file->bson_##name.len) { \ return &file->bson_##name; \ } else { \ return NULL; \ } \ } \ void \ mongoc_gridfs_file_set_##name (mongoc_gridfs_file_t * file, \ const bson_t * bson) \ { \ if (file->name.len) { \ bson_destroy (&file->name); \ } \ bson_copy_to (bson, &(file->name)); \ file->is_dirty = 1; \ } MONGOC_GRIDFS_FILE_STR_ACCESSOR (md5) MONGOC_GRIDFS_FILE_STR_ACCESSOR (filename) MONGOC_GRIDFS_FILE_STR_ACCESSOR (content_type) MONGOC_GRIDFS_FILE_BSON_ACCESSOR (aliases) MONGOC_GRIDFS_FILE_BSON_ACCESSOR (metadata) /** save a gridfs file */ bool mongoc_gridfs_file_save (mongoc_gridfs_file_t *file) { bson_t *selector, *update, child; const char *md5; const char *filename; const char *content_type; const bson_t *aliases; const bson_t *metadata; bool r; ENTRY; if (!file->is_dirty) { return 1; } if (file->page && _mongoc_gridfs_file_page_is_dirty (file->page)) { _mongoc_gridfs_file_flush_page (file); } md5 = mongoc_gridfs_file_get_md5 (file); filename = mongoc_gridfs_file_get_filename (file); content_type = mongoc_gridfs_file_get_content_type (file); aliases = mongoc_gridfs_file_get_aliases (file); metadata = mongoc_gridfs_file_get_metadata (file); selector = bson_new (); bson_append_value (selector, "_id", -1, &file->files_id); update = bson_new (); bson_append_document_begin (update, "$set", -1, &child); bson_append_int64 (&child, "length", -1, file->length); bson_append_int32 (&child, "chunkSize", -1, file->chunk_size); bson_append_date_time (&child, "uploadDate", -1, file->upload_date); if (md5) { bson_append_utf8 (&child, "md5", -1, md5, -1); } if (filename) { bson_append_utf8 (&child, "filename", -1, filename, -1); } if (content_type) { bson_append_utf8 (&child, "contentType", -1, content_type, -1); } if (aliases) { bson_append_array (&child, "aliases", -1, aliases); } if (metadata) { bson_append_document (&child, "metadata", -1, metadata); } bson_append_document_end (update, &child); r = mongoc_collection_update (file->gridfs->files, MONGOC_UPDATE_UPSERT, selector, update, NULL, &file->error); bson_destroy (selector); bson_destroy (update); file->is_dirty = 0; RETURN (r); } /** * _mongoc_gridfs_file_new_from_bson: * * creates a gridfs file from a bson object * * This is only really useful for instantiating a gridfs file from a server * side object */ mongoc_gridfs_file_t * _mongoc_gridfs_file_new_from_bson (mongoc_gridfs_t *gridfs, const bson_t *data) { mongoc_gridfs_file_t *file; const bson_value_t *value; const char *key; bson_iter_t iter; const uint8_t *buf; uint32_t buf_len; ENTRY; BSON_ASSERT (gridfs); BSON_ASSERT (data); file = (mongoc_gridfs_file_t *)bson_malloc0 (sizeof *file); file->gridfs = gridfs; bson_copy_to (data, &file->bson); bson_iter_init (&iter, &file->bson); while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (0 == strcmp (key, "_id")) { value = bson_iter_value (&iter); bson_value_copy (value, &file->files_id); } else if (0 == strcmp (key, "length")) { if (!BSON_ITER_HOLDS_INT32 (&iter) && !BSON_ITER_HOLDS_INT64 (&iter) && !BSON_ITER_HOLDS_DOUBLE (&iter)) { GOTO (failure); } file->length = bson_iter_as_int64 (&iter); } else if (0 == strcmp (key, "chunkSize")) { if (!BSON_ITER_HOLDS_INT32 (&iter) && !BSON_ITER_HOLDS_INT64 (&iter) && !BSON_ITER_HOLDS_DOUBLE (&iter)) { GOTO (failure); } if (bson_iter_as_int64 (&iter) > INT32_MAX) { GOTO (failure); } file->chunk_size = (int32_t)bson_iter_as_int64 (&iter); } else if (0 == strcmp (key, "uploadDate")) { if (!BSON_ITER_HOLDS_DATE_TIME (&iter)){ GOTO (failure); } file->upload_date = bson_iter_date_time (&iter); } else if (0 == strcmp (key, "md5")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { GOTO (failure); } file->bson_md5 = bson_iter_utf8 (&iter, NULL); } else if (0 == strcmp (key, "filename")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { GOTO (failure); } file->bson_filename = bson_iter_utf8 (&iter, NULL); } else if (0 == strcmp (key, "contentType")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { GOTO (failure); } file->bson_content_type = bson_iter_utf8 (&iter, NULL); } else if (0 == strcmp (key, "aliases")) { if (!BSON_ITER_HOLDS_ARRAY (&iter)) { GOTO (failure); } bson_iter_array (&iter, &buf_len, &buf); bson_init_static (&file->bson_aliases, buf, buf_len); } else if (0 == strcmp (key, "metadata")) { if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { GOTO (failure); } bson_iter_document (&iter, &buf_len, &buf); bson_init_static (&file->bson_metadata, buf, buf_len); } } /* TODO: is there are a minimal object we should be verifying that we * actually have here? */ RETURN (file); failure: bson_destroy (&file->bson); RETURN (NULL); } /** * _mongoc_gridfs_file_new: * * Create a new empty gridfs file */ mongoc_gridfs_file_t * _mongoc_gridfs_file_new (mongoc_gridfs_t *gridfs, mongoc_gridfs_file_opt_t *opt) { mongoc_gridfs_file_t *file; mongoc_gridfs_file_opt_t default_opt = { 0 }; ENTRY; BSON_ASSERT (gridfs); if (!opt) { opt = &default_opt; } file = (mongoc_gridfs_file_t *)bson_malloc0 (sizeof *file); file->gridfs = gridfs; file->is_dirty = 1; if (opt->chunk_size) { file->chunk_size = opt->chunk_size; } else { /* * The default chunk size is now 255kb. This used to be 256k but has been * reduced to allow for them to fit within power of two sizes in mongod. * * See CDRIVER-322. */ file->chunk_size = (1 << 18) - 1024; } file->files_id.value_type = BSON_TYPE_OID; bson_oid_init (&file->files_id.value.v_oid, NULL); file->upload_date = time (NULL) * 1000; if (opt->md5) { file->md5 = bson_strdup (opt->md5); } if (opt->filename) { file->filename = bson_strdup (opt->filename); } if (opt->content_type) { file->content_type = bson_strdup (opt->content_type); } if (opt->aliases) { bson_copy_to (opt->aliases, &(file->aliases)); } if (opt->metadata) { bson_copy_to (opt->metadata, &(file->metadata)); } file->pos = 0; file->n = 0; RETURN (file); } void mongoc_gridfs_file_destroy (mongoc_gridfs_file_t *file) { ENTRY; BSON_ASSERT (file); if (file->page) { _mongoc_gridfs_file_page_destroy (file->page); } if (file->bson.len) { bson_destroy (&file->bson); } if (file->cursor) { mongoc_cursor_destroy (file->cursor); } if (file->files_id.value_type) { bson_value_destroy (&file->files_id); } if (file->md5) { bson_free (file->md5); } if (file->filename) { bson_free (file->filename); } if (file->content_type) { bson_free (file->content_type); } if (file->aliases.len) { bson_destroy (&file->aliases); } if (file->bson_aliases.len) { bson_destroy (&file->bson_aliases); } if (file->metadata.len) { bson_destroy (&file->metadata); } if (file->bson_metadata.len) { bson_destroy (&file->bson_metadata); } bson_free (file); EXIT; } /** readv against a gridfs file */ ssize_t mongoc_gridfs_file_readv (mongoc_gridfs_file_t *file, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, uint32_t timeout_msec) { uint32_t bytes_read = 0; int32_t r; size_t i; uint32_t iov_pos; ENTRY; BSON_ASSERT (file); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (timeout_msec <= INT_MAX); /* TODO: we should probably do something about timeout_msec here */ /* Reading when positioned past the end does nothing */ if (file->pos >= file->length) { return 0; } /* Try to get the current chunk */ if (!file->page && !_mongoc_gridfs_file_refresh_page (file)) { return -1; } for (i = 0; i < iovcnt; i++) { iov_pos = 0; for (;; ) { r = _mongoc_gridfs_file_page_read (file->page, (uint8_t *)iov[i].iov_base + iov_pos, (uint32_t)(iov[i].iov_len - iov_pos)); BSON_ASSERT (r >= 0); iov_pos += r; file->pos += r; bytes_read += r; if (iov_pos == iov[i].iov_len) { /* filled a bucket, keep going */ break; } else if (file->length == file->pos) { /* we're at the end of the file. So we're done */ RETURN (bytes_read); } else if (bytes_read >= min_bytes) { /* we need a new page, but we've read enough bytes to stop */ RETURN (bytes_read); } else if (!_mongoc_gridfs_file_refresh_page (file)) { /* more to read, just on a new page */ return -1; } } } RETURN (bytes_read); } /** writev against a gridfs file */ ssize_t mongoc_gridfs_file_writev (mongoc_gridfs_file_t *file, mongoc_iovec_t *iov, size_t iovcnt, uint32_t timeout_msec) { uint32_t bytes_written = 0; int32_t r; size_t i; uint32_t iov_pos; ENTRY; BSON_ASSERT (file); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (timeout_msec <= INT_MAX); /* TODO: we should probably do something about timeout_msec here */ /* Pull in the correct page */ if (!file->page && !_mongoc_gridfs_file_refresh_page (file)) { return -1; } /* When writing past the end-of-file, fill the gap with zeros */ if (file->pos > file->length && !_mongoc_gridfs_file_extend (file)) { return -1; } for (i = 0; i < iovcnt; i++) { iov_pos = 0; for (;; ) { if (!file->page && !_mongoc_gridfs_file_refresh_page (file)) { return -1; } /* write bytes until an iov is exhausted or the page is full */ r = _mongoc_gridfs_file_page_write (file->page, (uint8_t *)iov[i].iov_base + iov_pos, (uint32_t)(iov[i].iov_len - iov_pos)); BSON_ASSERT (r >= 0); iov_pos += r; file->pos += r; bytes_written += r; file->length = BSON_MAX (file->length, (int64_t)file->pos); if (iov_pos == iov[i].iov_len) { /** filled a bucket, keep going */ break; } else { /** flush the buffer, the next pass through will bring in a new page */ _mongoc_gridfs_file_flush_page (file); } } } file->is_dirty = 1; RETURN (bytes_written); } /** * _mongoc_gridfs_file_extend: * * Extend a GridFS file to the current position pointer. Zeros will be * appended to the end of the file until file->length is even with file->pos. * * If file->length >= file->pos, the function exits successfully with no * operation performed. * * Parameters: * @file: A mongoc_gridfs_file_t. * * Returns: * The number of zero bytes written, or -1 on failure. */ static ssize_t _mongoc_gridfs_file_extend (mongoc_gridfs_file_t *file) { int64_t target_length; ssize_t diff; ENTRY; BSON_ASSERT (file); if (file->length >= file->pos) { RETURN (0); } diff = (ssize_t)(file->pos - file->length); target_length = file->pos; mongoc_gridfs_file_seek (file, 0, SEEK_END); while (true) { if (!file->page && !_mongoc_gridfs_file_refresh_page (file)) { RETURN (-1); } /* Set bytes until we reach the limit or fill a page */ file->pos += _mongoc_gridfs_file_page_memset0 (file->page, target_length - file->pos); if (file->pos == target_length) { /* We're done */ break; } else if (!_mongoc_gridfs_file_flush_page (file)) { /* We tried to flush a full buffer, but an error occurred */ RETURN (-1); } } BSON_ASSERT (file->length = target_length); file->is_dirty = true; RETURN (diff); } /** * _mongoc_gridfs_file_flush_page: * * Unconditionally flushes the file's current page to the database. * The page to flush is determined by page->n. * * Side Effects: * * On success, file->page is properly destroyed and set to NULL. * * Returns: * * True on success; false otherwise. */ static bool _mongoc_gridfs_file_flush_page (mongoc_gridfs_file_t *file) { bson_t *selector, *update; bool r; const uint8_t *buf; uint32_t len; ENTRY; BSON_ASSERT (file); BSON_ASSERT (file->page); buf = _mongoc_gridfs_file_page_get_data (file->page); len = _mongoc_gridfs_file_page_get_len (file->page); selector = bson_new (); bson_append_value (selector, "files_id", -1, &file->files_id); bson_append_int32 (selector, "n", -1, file->n); update = bson_sized_new (file->chunk_size + 100); bson_append_value (update, "files_id", -1, &file->files_id); bson_append_int32 (update, "n", -1, file->n); bson_append_binary (update, "data", -1, BSON_SUBTYPE_BINARY, buf, len); r = mongoc_collection_update (file->gridfs->chunks, MONGOC_UPDATE_UPSERT, selector, update, NULL, &file->error); bson_destroy (selector); bson_destroy (update); if (r) { _mongoc_gridfs_file_page_destroy (file->page); file->page = NULL; r = mongoc_gridfs_file_save (file); } RETURN (r); } /** * _mongoc_gridfs_file_keep_cursor: * * After a seek, decide if the next read should use the current cursor or * start a new query. * * Preconditions: * * file has a cursor and cursor range. * * Side Effects: * * None. */ static bool _mongoc_gridfs_file_keep_cursor (mongoc_gridfs_file_t *file) { uint32_t chunk_no; uint32_t chunks_per_batch; if (file->n < 0 || file->chunk_size <= 0) { return false; } chunk_no = (uint32_t) file->n; /* server returns roughly 4 MB batches by default */ chunks_per_batch = (4 * 1024 * 1024) / (uint32_t) file->chunk_size; return ( /* cursor is on or before the desired chunk */ file->cursor_range[0] <= chunk_no && /* chunk_no is before end of file */ chunk_no <= file->cursor_range[1] && /* desired chunk is in this batch or next one */ chunk_no < file->cursor_range[0] + 2 * chunks_per_batch); } /** * _mongoc_gridfs_file_refresh_page: * * Refresh a GridFS file's underlying page. This recalculates the current * page number based on the file's stream position, then fetches that page * from the database. * * Note that this fetch is unconditional and the page is queried from the * database even if the current page covers the same theoretical chunk. * * * Side Effects: * * file->page is loaded with the appropriate buffer, fetched from the * database. If the file position is at the end of the file and on a new * chunk boundary, a new page is created. We currently DO NOT handle the case * of the file position being far past the end-of-file. * * file->n is set based on file->pos. file->error is set on error. */ static bool _mongoc_gridfs_file_refresh_page (mongoc_gridfs_file_t *file) { bson_t *query, *fields, child, child2; const bson_t *chunk; const char *key; bson_iter_t iter; const uint8_t *data; uint32_t len; ENTRY; BSON_ASSERT (file); file->n = (int32_t)(file->pos / file->chunk_size); if (file->page) { _mongoc_gridfs_file_page_destroy (file->page); file->page = NULL; } /* if the file pointer is past the end of the current file (I.e. pointing to * a new chunk) and we're on a chunk boundary, we'll pass the page * constructor a new empty page */ if ((int64_t)file->pos >= file->length && !(file->pos % file->chunk_size)) { data = (uint8_t *)""; len = 0; } else { /* if we have a cursor, but the cursor doesn't have the chunk we're going * to need, destroy it (we'll grab a new one immediately there after) */ if (file->cursor && !_mongoc_gridfs_file_keep_cursor (file)) { mongoc_cursor_destroy (file->cursor); file->cursor = NULL; } if (!file->cursor) { query = bson_new (); bson_append_document_begin(query, "$query", -1, &child); bson_append_value (&child, "files_id", -1, &file->files_id); bson_append_document_begin (&child, "n", -1, &child2); bson_append_int32 (&child2, "$gte", -1, file->n); bson_append_document_end (&child, &child2); bson_append_document_end(query, &child); bson_append_document_begin(query, "$orderby", -1, &child); bson_append_int32 (&child, "n", -1, 1); bson_append_document_end(query, &child); fields = bson_new (); bson_append_int32 (fields, "n", -1, 1); bson_append_int32 (fields, "data", -1, 1); bson_append_int32 (fields, "_id", -1, 0); /* find all chunks greater than or equal to our current file pos */ file->cursor = mongoc_collection_find (file->gridfs->chunks, MONGOC_QUERY_NONE, 0, 0, 0, query, fields, NULL); file->cursor_range[0] = file->n; file->cursor_range[1] = (uint32_t)(file->length / file->chunk_size); bson_destroy (query); bson_destroy (fields); BSON_ASSERT (file->cursor); } /* we might have had a cursor before, then seeked ahead past a chunk. * iterate until we're on the right chunk */ while (file->cursor_range[0] <= file->n) { if (!mongoc_cursor_next (file->cursor, &chunk)) { /* copy cursor error, if any. might just lack a matching chunk. */ mongoc_cursor_error (file->cursor, &file->error); RETURN (0); } file->cursor_range[0]++; } bson_iter_init (&iter, chunk); /* grab out what we need from the chunk */ while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (strcmp (key, "n") == 0) { if (file->n != bson_iter_int32 (&iter)) { bson_set_error (&file->error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CHUNK_MISSING, "missing chunk number %" PRId32, file->n); RETURN (0); } } else if (strcmp (key, "data") == 0) { bson_iter_binary (&iter, NULL, &len, &data); } else { /* Unexpected key. This should never happen */ RETURN (0); } } if (file->n != file->pos / file->chunk_size) { return 0; } } file->page = _mongoc_gridfs_file_page_new (data, len, file->chunk_size); /* seek in the page towards wherever we're supposed to be */ RETURN (_mongoc_gridfs_file_page_seek (file->page, file->pos % file->chunk_size)); } /** * mongoc_gridfs_file_seek: * * Adjust the file position pointer in `file` by `delta`, starting from the * position `whence`. The `whence` argument is interpreted as in fseek(2): * * SEEK_SET Set the position relative to the start of the file. * SEEK_CUR Move `delta` from the current file position. * SEEK_END Move `delta` from the end-of-file. * * Parameters: * * @file: A mongoc_gridfs_file_t. * @delta: The amount to move. May be positive or negative. * @whence: One of SEEK_SET, SEEK_CUR or SEEK_END. * * Errors: * * [EINVAL] `whence` is not one of SEEK_SET, SEEK_CUR or SEEK_END. * [EINVAL] Resulting file position would be negative. * * Side Effects: * * On success, the file's underlying position pointer is set appropriately. * On failure, the file position is NOT changed and errno is set. * * Returns: * * 0 on success. * -1 on error, and errno set to indicate the error. */ int mongoc_gridfs_file_seek (mongoc_gridfs_file_t *file, int64_t delta, int whence) { int64_t offset; BSON_ASSERT (file); switch (whence) { case SEEK_SET: offset = delta; break; case SEEK_CUR: offset = file->pos + delta; break; case SEEK_END: offset = file->length + delta; break; default: errno = EINVAL; return -1; break; } if (offset < 0) { errno = EINVAL; return -1; } if (offset / file->chunk_size != file->n) { /** no longer on the same page */ if (file->page) { if (_mongoc_gridfs_file_page_is_dirty (file->page)) { _mongoc_gridfs_file_flush_page (file); } else { _mongoc_gridfs_file_page_destroy (file->page); file->page = NULL; } } /** we'll pick up the seek when we fetch a page on the next action. We lazily load */ } else if (file->page) { _mongoc_gridfs_file_page_seek (file->page, offset % file->chunk_size); } file->pos = offset; file->n = file->pos / file->chunk_size; return 0; } uint64_t mongoc_gridfs_file_tell (mongoc_gridfs_file_t *file) { BSON_ASSERT(file); return file->pos; } bool mongoc_gridfs_file_error (mongoc_gridfs_file_t *file, bson_error_t *error) { BSON_ASSERT(file); BSON_ASSERT(error); if (BSON_UNLIKELY(file->error.domain)) { bson_set_error(error, file->error.domain, file->error.code, "%s", file->error.message); RETURN(true); } RETURN(false); } const bson_value_t * mongoc_gridfs_file_get_id (mongoc_gridfs_file_t *file) { BSON_ASSERT (file); return &file->files_id; } int64_t mongoc_gridfs_file_get_length (mongoc_gridfs_file_t *file) { BSON_ASSERT (file); return file->length; } int32_t mongoc_gridfs_file_get_chunk_size (mongoc_gridfs_file_t *file) { BSON_ASSERT (file); return file->chunk_size; } int64_t mongoc_gridfs_file_get_upload_date (mongoc_gridfs_file_t *file) { BSON_ASSERT (file); return file->upload_date; } bool mongoc_gridfs_file_remove (mongoc_gridfs_file_t *file, bson_error_t *error) { bson_t sel = BSON_INITIALIZER; bool ret = false; BSON_ASSERT (file); BSON_APPEND_VALUE (&sel, "_id", &file->files_id); if (!mongoc_collection_remove (file->gridfs->files, MONGOC_REMOVE_SINGLE_REMOVE, &sel, NULL, error)) { goto cleanup; } bson_reinit (&sel); BSON_APPEND_VALUE (&sel, "files_id", &file->files_id); if (!mongoc_collection_remove (file->gridfs->chunks, MONGOC_REMOVE_NONE, &sel, NULL, error)) { goto cleanup; } ret = true; cleanup: bson_destroy (&sel); return ret; } libmongoc-1.3.1/src/mongoc/mongoc-gridfs-file.h000066400000000000000000000064761264720626300214070ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_GRIDFS_FILE_H #define MONGOC_GRIDFS_FILE_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-socket.h" BSON_BEGIN_DECLS #define MONGOC_GRIDFS_FILE_STR_HEADER(name) \ const char * \ mongoc_gridfs_file_get_##name (mongoc_gridfs_file_t * file); \ void \ mongoc_gridfs_file_set_##name (mongoc_gridfs_file_t * file, \ const char *str); #define MONGOC_GRIDFS_FILE_BSON_HEADER(name) \ const bson_t * \ mongoc_gridfs_file_get_##name (mongoc_gridfs_file_t * file); \ void \ mongoc_gridfs_file_set_##name (mongoc_gridfs_file_t * file, \ const bson_t * bson); typedef struct _mongoc_gridfs_file_t mongoc_gridfs_file_t; typedef struct _mongoc_gridfs_file_opt_t mongoc_gridfs_file_opt_t; struct _mongoc_gridfs_file_opt_t { const char *md5; const char *filename; const char *content_type; const bson_t *aliases; const bson_t *metadata; uint32_t chunk_size; }; MONGOC_GRIDFS_FILE_STR_HEADER (md5) MONGOC_GRIDFS_FILE_STR_HEADER (filename) MONGOC_GRIDFS_FILE_STR_HEADER (content_type) MONGOC_GRIDFS_FILE_BSON_HEADER (aliases) MONGOC_GRIDFS_FILE_BSON_HEADER (metadata) const bson_value_t * mongoc_gridfs_file_get_id (mongoc_gridfs_file_t * file); int64_t mongoc_gridfs_file_get_length (mongoc_gridfs_file_t *file); int32_t mongoc_gridfs_file_get_chunk_size (mongoc_gridfs_file_t *file); int64_t mongoc_gridfs_file_get_upload_date (mongoc_gridfs_file_t *file); ssize_t mongoc_gridfs_file_writev (mongoc_gridfs_file_t *file, mongoc_iovec_t *iov, size_t iovcnt, uint32_t timeout_msec); ssize_t mongoc_gridfs_file_readv (mongoc_gridfs_file_t *file, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, uint32_t timeout_msec); int mongoc_gridfs_file_seek (mongoc_gridfs_file_t *file, int64_t delta, int whence); uint64_t mongoc_gridfs_file_tell (mongoc_gridfs_file_t *file); bool mongoc_gridfs_file_save (mongoc_gridfs_file_t *file); void mongoc_gridfs_file_destroy (mongoc_gridfs_file_t *file); bool mongoc_gridfs_file_error (mongoc_gridfs_file_t *file, bson_error_t *error); bool mongoc_gridfs_file_remove (mongoc_gridfs_file_t *file, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_H */ libmongoc-1.3.1/src/mongoc/mongoc-gridfs-private.h000066400000000000000000000025021264720626300221240ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_GRIDFS_PRIVATE_H #define MONGOC_GRIDFS_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-read-prefs.h" #include "mongoc-write-concern.h" #include "mongoc-client.h" BSON_BEGIN_DECLS struct _mongoc_gridfs_t { mongoc_client_t *client; mongoc_collection_t *files; mongoc_collection_t *chunks; }; mongoc_gridfs_t *_mongoc_gridfs_new (mongoc_client_t *client, const char *db, const char *prefix, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_GRIDFS_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-gridfs.c000066400000000000000000000236651264720626300204640ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs" #include "mongoc-bulk-operation.h" #include "mongoc-client-private.h" #include "mongoc-collection.h" #include "mongoc-collection-private.h" #include "mongoc-error.h" #include "mongoc-index.h" #include "mongoc-gridfs.h" #include "mongoc-gridfs-private.h" #include "mongoc-gridfs-file.h" #include "mongoc-gridfs-file-private.h" #include "mongoc-gridfs-file-list.h" #include "mongoc-gridfs-file-list-private.h" #include "mongoc-client.h" #include "mongoc-trace.h" #define MONGOC_GRIDFS_STREAM_CHUNK 4096 /** * _mongoc_gridfs_ensure_index: * * ensure gridfs indexes * * Ensure fast searches for chunks via [ files_id, n ] * Ensure fast searches for files via [ filename ] */ static bool _mongoc_gridfs_ensure_index (mongoc_gridfs_t *gridfs, bson_error_t *error) { bson_t keys; mongoc_index_opt_t opt; bool r; ENTRY; bson_init (&keys); bson_append_int32 (&keys, "files_id", -1, 1); bson_append_int32 (&keys, "n", -1, 1); mongoc_index_opt_init (&opt); opt.unique = 1; r = mongoc_collection_create_index (gridfs->chunks, &keys, &opt, error); bson_destroy (&keys); if (!r) { RETURN (r); } bson_init (&keys); bson_append_int32 (&keys, "filename", -1, 1); opt.unique = 0; r = mongoc_collection_create_index (gridfs->chunks, &keys, &opt, error); bson_destroy (&keys); if (!r) { RETURN (r); } RETURN (1); } mongoc_gridfs_t * _mongoc_gridfs_new (mongoc_client_t *client, const char *db, const char *prefix, bson_error_t *error) { mongoc_gridfs_t *gridfs; const mongoc_read_prefs_t *read_prefs; const mongoc_read_concern_t *read_concern; const mongoc_write_concern_t *write_concern; char buf[128]; bool r; ENTRY; BSON_ASSERT (client); BSON_ASSERT (db); if (!prefix) { prefix = "fs"; } /* make sure prefix is short enough to bucket the chunks and files * collections */ #ifndef BSON_DISABLE_ASSERT { uint32_t prefix_len; prefix_len = (uint32_t)strlen (prefix); BSON_ASSERT (prefix_len + sizeof (".chunks") < sizeof (buf)); } #endif gridfs = (mongoc_gridfs_t *) bson_malloc0 (sizeof *gridfs); gridfs->client = client; read_prefs = mongoc_client_get_read_prefs (client); read_concern = mongoc_client_get_read_concern (client); write_concern = mongoc_client_get_write_concern (client); bson_snprintf (buf, sizeof(buf), "%s.chunks", prefix); gridfs->chunks = _mongoc_collection_new (client, db, buf, read_prefs, read_concern, write_concern); bson_snprintf (buf, sizeof(buf), "%s.files", prefix); gridfs->files = _mongoc_collection_new (client, db, buf, read_prefs, read_concern, write_concern); r = _mongoc_gridfs_ensure_index (gridfs, error); if (!r) { mongoc_gridfs_destroy (gridfs); RETURN (NULL); } RETURN (gridfs); } bool mongoc_gridfs_drop (mongoc_gridfs_t *gridfs, bson_error_t *error) { bool r; ENTRY; r = mongoc_collection_drop (gridfs->files, error); if (!r) { RETURN (0); } r = mongoc_collection_drop (gridfs->chunks, error); if (!r) { RETURN (0); } RETURN (1); } void mongoc_gridfs_destroy (mongoc_gridfs_t *gridfs) { ENTRY; BSON_ASSERT (gridfs); mongoc_collection_destroy (gridfs->files); mongoc_collection_destroy (gridfs->chunks); bson_free (gridfs); EXIT; } /** find all matching gridfs files */ mongoc_gridfs_file_list_t * mongoc_gridfs_find (mongoc_gridfs_t *gridfs, const bson_t *query) { return _mongoc_gridfs_file_list_new (gridfs, query, 0); } /** find a single gridfs file */ mongoc_gridfs_file_t * mongoc_gridfs_find_one (mongoc_gridfs_t *gridfs, const bson_t *query, bson_error_t *error) { mongoc_gridfs_file_list_t *list; mongoc_gridfs_file_t *file; ENTRY; list = _mongoc_gridfs_file_list_new (gridfs, query, 1); file = mongoc_gridfs_file_list_next (list); mongoc_gridfs_file_list_error(list, error); mongoc_gridfs_file_list_destroy (list); RETURN (file); } /** find a single gridfs file by filename */ mongoc_gridfs_file_t * mongoc_gridfs_find_one_by_filename (mongoc_gridfs_t *gridfs, const char *filename, bson_error_t *error) { mongoc_gridfs_file_t *file; bson_t query; bson_init (&query); bson_append_utf8 (&query, "filename", -1, filename, -1); file = mongoc_gridfs_find_one (gridfs, &query, error); bson_destroy (&query); return file; } /** create a gridfs file from a stream * * The stream is fully consumed in creating the file */ mongoc_gridfs_file_t * mongoc_gridfs_create_file_from_stream (mongoc_gridfs_t *gridfs, mongoc_stream_t *stream, mongoc_gridfs_file_opt_t *opt) { mongoc_gridfs_file_t *file; ssize_t r; uint8_t buf[MONGOC_GRIDFS_STREAM_CHUNK]; mongoc_iovec_t iov; int timeout; ENTRY; BSON_ASSERT (gridfs); BSON_ASSERT (stream); iov.iov_base = (void *)buf; iov.iov_len = 0; file = _mongoc_gridfs_file_new (gridfs, opt); timeout = gridfs->client->cluster.sockettimeoutms; for (;; ) { r = mongoc_stream_read (stream, iov.iov_base, MONGOC_GRIDFS_STREAM_CHUNK, 0, timeout); if (r > 0) { iov.iov_len = r; mongoc_gridfs_file_writev (file, &iov, 1, timeout); } else if (r == 0) { break; } else { mongoc_gridfs_file_destroy (file); RETURN (NULL); } } mongoc_stream_failed (stream); mongoc_gridfs_file_seek (file, 0, SEEK_SET); RETURN (file); } /** create an empty gridfs file */ mongoc_gridfs_file_t * mongoc_gridfs_create_file (mongoc_gridfs_t *gridfs, mongoc_gridfs_file_opt_t *opt) { mongoc_gridfs_file_t *file; ENTRY; BSON_ASSERT (gridfs); file = _mongoc_gridfs_file_new (gridfs, opt); RETURN (file); } /** accessor functions for collections */ mongoc_collection_t * mongoc_gridfs_get_files (mongoc_gridfs_t *gridfs) { BSON_ASSERT (gridfs); return gridfs->files; } mongoc_collection_t * mongoc_gridfs_get_chunks (mongoc_gridfs_t *gridfs) { BSON_ASSERT (gridfs); return gridfs->chunks; } bool mongoc_gridfs_remove_by_filename (mongoc_gridfs_t *gridfs, const char *filename, bson_error_t *error) { mongoc_bulk_operation_t *bulk_files = NULL; mongoc_bulk_operation_t *bulk_chunks = NULL; mongoc_cursor_t *cursor = NULL; bson_error_t files_error; bson_error_t chunks_error; const bson_t *doc; const char *key; char keybuf[16]; int count = 0; bool chunks_ret; bool files_ret; bool ret = false; bson_iter_t iter; bson_t *files_q = NULL; bson_t *chunks_q = NULL; bson_t q = BSON_INITIALIZER; bson_t fields = BSON_INITIALIZER; bson_t ar = BSON_INITIALIZER; BSON_ASSERT (gridfs); if (!filename) { bson_set_error (error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_INVALID_FILENAME, "A non-NULL filename must be specified."); return false; } /* * Find all files matching this filename. Hopefully just one, but not * strictly required! */ BSON_APPEND_UTF8 (&q, "filename", filename); BSON_APPEND_INT32 (&fields, "_id", 1); cursor = mongoc_collection_find (gridfs->files, MONGOC_QUERY_NONE, 0, 0, 0, &q, &fields, NULL); BSON_ASSERT (cursor); while (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init_find (&iter, doc, "_id")) { const bson_value_t *value = bson_iter_value (&iter); bson_uint32_to_string (count, &key, keybuf, sizeof keybuf); BSON_APPEND_VALUE (&ar, key, value); } } if (mongoc_cursor_error (cursor, error)) { goto failure; } bulk_files = mongoc_collection_create_bulk_operation (gridfs->files, false, NULL); bulk_chunks = mongoc_collection_create_bulk_operation (gridfs->chunks, false, NULL); files_q = BCON_NEW ("_id", "{", "$in", BCON_ARRAY (&ar), "}"); chunks_q = BCON_NEW ("files_id", "{", "$in", BCON_ARRAY (&ar), "}"); mongoc_bulk_operation_remove (bulk_files, files_q); mongoc_bulk_operation_remove (bulk_chunks, chunks_q); files_ret = mongoc_bulk_operation_execute (bulk_files, NULL, &files_error); chunks_ret = mongoc_bulk_operation_execute (bulk_chunks, NULL, &chunks_error); if (error) { if (!files_ret) { memcpy (error, &files_error, sizeof *error); } else if (!chunks_ret) { memcpy (error, &chunks_error, sizeof *error); } } ret = (files_ret && chunks_ret); failure: if (cursor) { mongoc_cursor_destroy (cursor); } if (bulk_files) { mongoc_bulk_operation_destroy (bulk_files); } if (bulk_chunks) { mongoc_bulk_operation_destroy (bulk_chunks); } bson_destroy (&q); bson_destroy (&fields); bson_destroy (&ar); if (files_q) { bson_destroy (files_q); } if (chunks_q) { bson_destroy (chunks_q); } return ret; } libmongoc-1.3.1/src/mongoc/mongoc-gridfs.h000066400000000000000000000060761264720626300204660ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_GRIDFS_H #define MONGOC_GRIDFS_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-stream.h" #include "mongoc-gridfs-file.h" #include "mongoc-collection.h" #include "mongoc-gridfs-file-list.h" BSON_BEGIN_DECLS typedef struct _mongoc_gridfs_t mongoc_gridfs_t; mongoc_gridfs_file_t *mongoc_gridfs_create_file_from_stream (mongoc_gridfs_t *gridfs, mongoc_stream_t *stream, mongoc_gridfs_file_opt_t *opt); mongoc_gridfs_file_t *mongoc_gridfs_create_file (mongoc_gridfs_t *gridfs, mongoc_gridfs_file_opt_t *opt); mongoc_gridfs_file_list_t *mongoc_gridfs_find (mongoc_gridfs_t *gridfs, const bson_t *query); mongoc_gridfs_file_t *mongoc_gridfs_find_one (mongoc_gridfs_t *gridfs, const bson_t *query, bson_error_t *error); mongoc_gridfs_file_t *mongoc_gridfs_find_one_by_filename (mongoc_gridfs_t *gridfs, const char *filename, bson_error_t *error); bool mongoc_gridfs_drop (mongoc_gridfs_t *gridfs, bson_error_t *error); void mongoc_gridfs_destroy (mongoc_gridfs_t *gridfs); mongoc_collection_t *mongoc_gridfs_get_files (mongoc_gridfs_t *gridfs); mongoc_collection_t *mongoc_gridfs_get_chunks (mongoc_gridfs_t *gridfs); bool mongoc_gridfs_remove_by_filename (mongoc_gridfs_t *gridfs, const char *filename, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_GRIDFS_H */ libmongoc-1.3.1/src/mongoc/mongoc-host-list-private.h000066400000000000000000000023251264720626300225770ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_HOST_LIST_PRIVATE_H #define MONGOC_HOST_LIST_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include "mongoc-host-list.h" BSON_BEGIN_DECLS bool _mongoc_host_list_from_string (mongoc_host_list_t *host_list, const char *host_and_port); bool _mongoc_host_list_equal (const mongoc_host_list_t *host_a, const mongoc_host_list_t *host_b); void _mongoc_host_list_destroy_all (mongoc_host_list_t *host); BSON_END_DECLS #endif /* MONGOC_HOST_LIST_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-host-list.c000066400000000000000000000032631264720626300211240ustar00rootroot00000000000000/* * Copyright 2015 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-host-list-private.h" /* strcasecmp on windows */ #include "mongoc-util-private.h" /* *-------------------------------------------------------------------------- * * _mongoc_host_list_equal -- * * Check two hosts have the same domain (case-insensitive), port, * and address family. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool _mongoc_host_list_equal (const mongoc_host_list_t *host_a, const mongoc_host_list_t *host_b) { return (!strcasecmp (host_a->host_and_port, host_b->host_and_port) && host_a->family == host_b->family); } /* *-------------------------------------------------------------------------- * * _mongoc_host_list_destroy_all -- * * Destroy whole linked list of hosts. * *-------------------------------------------------------------------------- */ void _mongoc_host_list_destroy_all (mongoc_host_list_t *host) { mongoc_host_list_t *tmp; while (host) { tmp = host->next; bson_free (host); host = tmp; } } libmongoc-1.3.1/src/mongoc/mongoc-host-list.h000066400000000000000000000025671264720626300211370ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_HOST_LIST_H #define MONGOC_HOST_LIST_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS #ifndef HOST_NAME_MAX # ifdef _POSIX_HOST_NAME_MAX # define BSON_HOST_NAME_MAX _POSIX_HOST_NAME_MAX # else # define BSON_HOST_NAME_MAX 255 # endif #else # define BSON_HOST_NAME_MAX HOST_NAME_MAX #endif typedef struct _mongoc_host_list_t mongoc_host_list_t; struct _mongoc_host_list_t { mongoc_host_list_t *next; char host [BSON_HOST_NAME_MAX + 1]; char host_and_port [BSON_HOST_NAME_MAX + 7]; uint16_t port; int family; void *padding [4]; }; BSON_END_DECLS #endif /* MONGOC_HOST_LIST_H */ libmongoc-1.3.1/src/mongoc/mongoc-index.c000066400000000000000000000055321264720626300203060ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-index.h" #include "mongoc-trace.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs_index" static mongoc_index_opt_t gMongocIndexOptDefault = { 1, /* is_initialized */ 0, /* background */ 0, /* unique */ NULL, /* name */ 0, /* drop_dups */ 0, /* sparse */ -1, /* expire_after_seconds */ -1, /* v */ NULL, /* weights */ NULL, /* default_language */ NULL, /* language_override */ NULL, /* mongoc_index_opt_geo_t geo_options */ NULL, /* mongoc_index_opt_storage_t storage_options */ NULL, /* partial_filter_expression */ {NULL} /* struct padding */ }; static mongoc_index_opt_geo_t gMongocIndexOptGeoDefault = { 26, /* twod_sphere_version */ -90, /* twod_bits_precision */ 90, /* twod_location_min */ -1, /* twod_location_max */ 2, /* haystack_bucket_size */ {NULL} /* struct padding */ }; static mongoc_index_opt_wt_t gMongocIndexOptWTDefault = { { MONGOC_INDEX_STORAGE_OPT_WIREDTIGER }, /* mongoc_index_opt_storage_t */ "", /* config_str */ {NULL} /* struct padding */ }; const mongoc_index_opt_t * mongoc_index_opt_get_default (void) { return &gMongocIndexOptDefault; } const mongoc_index_opt_geo_t * mongoc_index_opt_geo_get_default (void) { return &gMongocIndexOptGeoDefault; } const mongoc_index_opt_wt_t * mongoc_index_opt_wt_get_default (void) { return &gMongocIndexOptWTDefault; } void mongoc_index_opt_init (mongoc_index_opt_t *opt) { BSON_ASSERT (opt); memcpy (opt, &gMongocIndexOptDefault, sizeof *opt); } void mongoc_index_opt_geo_init (mongoc_index_opt_geo_t *opt) { BSON_ASSERT (opt); memcpy (opt, &gMongocIndexOptGeoDefault, sizeof *opt); } void mongoc_index_opt_wt_init (mongoc_index_opt_wt_t *opt) { BSON_ASSERT(opt); memcpy (opt, &gMongocIndexOptWTDefault, sizeof *opt); } libmongoc-1.3.1/src/mongoc/mongoc-index.h000066400000000000000000000051611264720626300203110ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_INDEX_H #define MONGOC_INDEX_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef struct { uint8_t twod_sphere_version; uint8_t twod_bits_precision; double twod_location_min; double twod_location_max; double haystack_bucket_size; uint8_t *padding[32]; } mongoc_index_opt_geo_t; typedef struct { int type; } mongoc_index_opt_storage_t; typedef enum { MONGOC_INDEX_STORAGE_OPT_MMAPV1, MONGOC_INDEX_STORAGE_OPT_WIREDTIGER, } mongoc_index_storage_opt_type_t; typedef struct { mongoc_index_opt_storage_t base; const char *config_str; void *padding[8]; } mongoc_index_opt_wt_t; typedef struct { bool is_initialized; bool background; bool unique; const char *name; bool drop_dups; bool sparse; int32_t expire_after_seconds; int32_t v; const bson_t *weights; const char *default_language; const char *language_override; mongoc_index_opt_geo_t *geo_options; mongoc_index_opt_storage_t *storage_options; const bson_t *partial_filter_expression; void *padding[5]; } mongoc_index_opt_t; const mongoc_index_opt_t *mongoc_index_opt_get_default (void) BSON_GNUC_CONST; const mongoc_index_opt_geo_t *mongoc_index_opt_geo_get_default (void) BSON_GNUC_CONST; const mongoc_index_opt_wt_t *mongoc_index_opt_wt_get_default (void) BSON_GNUC_CONST; void mongoc_index_opt_init (mongoc_index_opt_t *opt); void mongoc_index_opt_geo_init (mongoc_index_opt_geo_t *opt); void mongoc_index_opt_wt_init (mongoc_index_opt_wt_t *opt); BSON_END_DECLS #endif /* MONGOC_INDEX_H */ libmongoc-1.3.1/src/mongoc/mongoc-init.c000066400000000000000000000066201264720626300201410ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-config.h" #include "mongoc-counters-private.h" #include "mongoc-init.h" #ifdef MONGOC_ENABLE_SSL # include "mongoc-scram-private.h" # include "mongoc-ssl.h" # include "mongoc-ssl-private.h" #endif #include "mongoc-thread-private.h" #include "mongoc-trace.h" #ifdef MONGOC_ENABLE_SASL #include static void * mongoc_sasl_mutex_alloc (void) { mongoc_mutex_t *mutex; mutex = (mongoc_mutex_t *)bson_malloc0 (sizeof (mongoc_mutex_t)); mongoc_mutex_init (mutex); return (void *) mutex; } static int mongoc_sasl_mutex_lock (void *mutex) { mongoc_mutex_lock ((mongoc_mutex_t *) mutex); return SASL_OK; } static int mongoc_sasl_mutex_unlock (void *mutex) { mongoc_mutex_unlock ((mongoc_mutex_t *) mutex); return SASL_OK; } static void mongoc_sasl_mutex_free (void *mutex) { mongoc_mutex_destroy ((mongoc_mutex_t *) mutex); bson_free (mutex); } #endif//MONGOC_ENABLE_SASL static MONGOC_ONCE_FUN( _mongoc_do_init) { #ifdef MONGOC_ENABLE_SSL _mongoc_ssl_init(); _mongoc_scram_startup(); #endif #ifdef MONGOC_ENABLE_SASL /* The following functions should not use tracing, as they may be invoked * before mongoc_log_set_handler() can complete. */ sasl_set_mutex (mongoc_sasl_mutex_alloc, mongoc_sasl_mutex_lock, mongoc_sasl_mutex_unlock, mongoc_sasl_mutex_free); /* TODO: logging callback? */ sasl_client_init (NULL); #endif _mongoc_counters_init(); #ifdef _WIN32 { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD (2, 2); err = WSAStartup (wVersionRequested, &wsaData); /* check the version perhaps? */ BSON_ASSERT (err == 0); } #endif MONGOC_ONCE_RETURN; } void mongoc_init (void) { static mongoc_once_t once = MONGOC_ONCE_INIT; mongoc_once (&once, _mongoc_do_init); } static MONGOC_ONCE_FUN( _mongoc_do_cleanup) { #ifdef MONGOC_ENABLE_SSL _mongoc_ssl_cleanup(); #endif #ifdef MONGOC_ENABLE_SASL #ifdef MONGOC_HAVE_SASL_CLIENT_DONE sasl_client_done (); #else /* fall back to deprecated function */ sasl_done (); #endif #endif #ifdef _WIN32 WSACleanup (); #endif _mongoc_counters_cleanup (); MONGOC_ONCE_RETURN; } void mongoc_cleanup (void) { static mongoc_once_t once = MONGOC_ONCE_INIT; mongoc_once (&once, _mongoc_do_cleanup); } /* * On GCC, just use __attribute__((constructor)) to perform initialization * automatically for the application. */ #if defined(__GNUC__) && ! defined(MONGOC_NO_AUTOMATIC_GLOBALS) static void _mongoc_init_ctor (void) __attribute__((constructor)); static void _mongoc_init_ctor (void) { mongoc_init (); } static void _mongoc_init_dtor (void) __attribute__((destructor)); static void _mongoc_init_dtor (void) { mongoc_cleanup (); } #endif libmongoc-1.3.1/src/mongoc/mongoc-init.h000066400000000000000000000016061264720626300201450ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_INIT_H #define MONGOC_INIT_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS void mongoc_init (void); void mongoc_cleanup(void); BSON_END_DECLS #endif /* MONGOC_INIT_H */ libmongoc-1.3.1/src/mongoc/mongoc-iovec.h000066400000000000000000000022161264720626300203050ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_IOVEC_H #define MONGOC_IOVEC_H #include #ifdef _WIN32 # include #else # include #endif BSON_BEGIN_DECLS #ifdef _WIN32 typedef struct { u_long iov_len; char *iov_base; } mongoc_iovec_t; BSON_STATIC_ASSERT(sizeof(mongoc_iovec_t) == sizeof(WSABUF)); BSON_STATIC_ASSERT(offsetof(mongoc_iovec_t, iov_base) == offsetof(WSABUF, buf)); BSON_STATIC_ASSERT(offsetof(mongoc_iovec_t, iov_len) == offsetof(WSABUF, len)); #else typedef struct iovec mongoc_iovec_t; #endif BSON_END_DECLS #endif /* MONGOC_IOVEC_H */ libmongoc-1.3.1/src/mongoc/mongoc-list-private.h000066400000000000000000000030671264720626300216300ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_LIST_H #define MONGOC_LIST_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef struct _mongoc_list_t mongoc_list_t; struct _mongoc_list_t { mongoc_list_t *next; void *data; }; mongoc_list_t *_mongoc_list_append (mongoc_list_t *list, void *data); mongoc_list_t *_mongoc_list_prepend (mongoc_list_t *list, void *data); mongoc_list_t *_mongoc_list_remove (mongoc_list_t *list, void *data); void _mongoc_list_foreach (mongoc_list_t *list, void (*func) (void *data, void *user_data), void * user_data); void _mongoc_list_destroy (mongoc_list_t *list); BSON_END_DECLS #endif /* MONGOC_LIST_H */ libmongoc-1.3.1/src/mongoc/mongoc-list.c000066400000000000000000000061671264720626300201570ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-list-private.h" /** * mongoc_list_append: * @list: A list to append to, or NULL. * @data: Data to append to @list. * * Appends a new link onto the linked list. * * Returns: @list or a new list if @list is NULL. */ mongoc_list_t * _mongoc_list_append (mongoc_list_t *list, void *data) { mongoc_list_t *item; mongoc_list_t *iter; item = (mongoc_list_t *)bson_malloc0(sizeof *item); item->data = (void *)data; if (!list) { return item; } for (iter = list; iter->next; iter = iter->next) { } iter->next = item; return list; } /** * mongoc_list_prepend: * @list: A mongoc_list_t or NULL. * @data: data to prepend to the list. * * Prepends to @list a new link containing @data. * * Returns: A new link containing data with @list following. */ mongoc_list_t * _mongoc_list_prepend (mongoc_list_t *list, void *data) { mongoc_list_t *item; item = (mongoc_list_t *)bson_malloc0(sizeof *item); item->data = (void *)data; item->next = list; return item; } /** * mongoc_list_remove: * @list: A mongoc_list_t. * @data: Data to remove from @list. * * Removes the link containing @data from @list. * * Returns: @list with the link containing @data removed. */ mongoc_list_t * _mongoc_list_remove (mongoc_list_t *list, void *data) { mongoc_list_t *iter; mongoc_list_t *prev = NULL; mongoc_list_t *ret = list; BSON_ASSERT (list); for (iter = list; iter; iter = iter->next) { if (iter->data == data) { if (iter != list) { prev->next = iter->next; } else { ret = iter->next; } bson_free(iter); break; } prev = iter; } return ret; } /** * mongoc_list_foreach: * @list: A mongoc_list_t or NULL. * @func: A func to call for each link in @list. * @user_data: User data for @func. * * Calls @func for each item in @list. */ void _mongoc_list_foreach (mongoc_list_t *list, void (*func) (void *data, void *user_data), void *user_data) { mongoc_list_t *iter; BSON_ASSERT (func); for (iter = list; iter; iter = iter->next) { func(iter->data, user_data); } } /** * mongoc_list_destroy: * @list: A mongoc_list_t. * * Destroys @list and releases any resources. */ void _mongoc_list_destroy (mongoc_list_t *list) { mongoc_list_t *tmp = list; while (list) { tmp = list->next; bson_free(list); list = tmp; } } libmongoc-1.3.1/src/mongoc/mongoc-log-private.h000066400000000000000000000026621264720626300214360ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_LOG_PRIVATE_H #define MONGOC_LOG_PRIVATE_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) && !defined (MONGOC_I_AM_A_DRIVER) # error "Only can be included directly." #endif #include "mongoc-iovec.h" /* just for testing */ void _mongoc_log_get_handler (mongoc_log_func_t *log_func, void **user_data); bool _mongoc_log_trace_is_enabled (void); void mongoc_log_trace_bytes (const char *domain, const uint8_t *_b, size_t _l); void mongoc_log_trace_iovec (const char *domain, const mongoc_iovec_t *_iov, size_t _iovcnt); void mongoc_log_trace_enable (void); void mongoc_log_trace_disable (void); #endif /* MONGOC_LOG_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-log.c000066400000000000000000000161351264720626300177610ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined(__linux__) # include #elif defined(_WIN32) # include #else # include #endif #include #include #include "mongoc-log.h" #include "mongoc-log-private.h" #include "mongoc-thread-private.h" static mongoc_mutex_t gLogMutex; static mongoc_log_func_t gLogFunc = mongoc_log_default_handler; #ifdef MONGOC_TRACE static bool gLogTrace = true; #endif static void *gLogData; static MONGOC_ONCE_FUN( _mongoc_ensure_mutex_once) { mongoc_mutex_init(&gLogMutex); MONGOC_ONCE_RETURN; } void mongoc_log_set_handler (mongoc_log_func_t log_func, void *user_data) { static mongoc_once_t once = MONGOC_ONCE_INIT; mongoc_once(&once, &_mongoc_ensure_mutex_once); mongoc_mutex_lock(&gLogMutex); gLogFunc = log_func; gLogData = user_data; mongoc_mutex_unlock(&gLogMutex); } /* just for testing */ void _mongoc_log_get_handler (mongoc_log_func_t *log_func, void **user_data) { *log_func = gLogFunc; *user_data = gLogData; } void mongoc_log (mongoc_log_level_t log_level, const char *log_domain, const char *format, ...) { va_list args; char *message; static mongoc_once_t once = MONGOC_ONCE_INIT; int stop_logging; mongoc_once(&once, &_mongoc_ensure_mutex_once); stop_logging = !gLogFunc; #ifdef MONGOC_TRACE stop_logging = stop_logging || (log_level == MONGOC_LOG_LEVEL_TRACE && !gLogTrace); #endif if (stop_logging) { return; } BSON_ASSERT (format); va_start(args, format); message = bson_strdupv_printf(format, args); va_end(args); mongoc_mutex_lock(&gLogMutex); gLogFunc(log_level, log_domain, message, gLogData); mongoc_mutex_unlock(&gLogMutex); bson_free(message); } const char * mongoc_log_level_str (mongoc_log_level_t log_level) { switch (log_level) { case MONGOC_LOG_LEVEL_ERROR: return "ERROR"; case MONGOC_LOG_LEVEL_CRITICAL: return "CRITICAL"; case MONGOC_LOG_LEVEL_WARNING: return "WARNING"; case MONGOC_LOG_LEVEL_MESSAGE: return "MESSAGE"; case MONGOC_LOG_LEVEL_INFO: return "INFO"; case MONGOC_LOG_LEVEL_DEBUG: return "DEBUG"; case MONGOC_LOG_LEVEL_TRACE: return "TRACE"; default: return "UNKNOWN"; } } void mongoc_log_default_handler (mongoc_log_level_t log_level, const char *log_domain, const char *message, void *user_data) { struct timeval tv; struct tm tt; time_t t; FILE *stream; char nowstr[32]; int pid; bson_gettimeofday(&tv); t = tv.tv_sec; #ifdef _WIN32 # ifdef _MSC_VER localtime_s(&tt, &t); # else tt = *(localtime(&t)); # endif #else localtime_r(&t, &tt); #endif strftime (nowstr, sizeof nowstr, "%Y/%m/%d %H:%M:%S", &tt); switch (log_level) { case MONGOC_LOG_LEVEL_ERROR: case MONGOC_LOG_LEVEL_CRITICAL: case MONGOC_LOG_LEVEL_WARNING: stream = stderr; break; case MONGOC_LOG_LEVEL_MESSAGE: case MONGOC_LOG_LEVEL_INFO: case MONGOC_LOG_LEVEL_DEBUG: case MONGOC_LOG_LEVEL_TRACE: default: stream = stdout; } #ifdef __linux__ pid = syscall (SYS_gettid); #elif defined(_WIN32) pid = (int)_getpid (); #else pid = (int)getpid (); #endif fprintf (stream, "%s.%04ld: [%5d]: %8s: %12s: %s\n", nowstr, tv.tv_usec / 1000L, pid, mongoc_log_level_str(log_level), log_domain, message); } bool _mongoc_log_trace_is_enabled (void) { #ifdef MONGOC_TRACE return gLogTrace; #else return false; #endif } void mongoc_log_trace_enable (void) { #ifdef MONGOC_TRACE gLogTrace = true; #endif } void mongoc_log_trace_disable (void) { #ifdef MONGOC_TRACE gLogTrace = false; #endif } void mongoc_log_trace_bytes (const char *domain, const uint8_t *_b, size_t _l) { bson_string_t *str, *astr; int32_t _i; uint8_t _v; #ifdef MONGOC_TRACE if (!gLogTrace) { return; } #endif str = bson_string_new(NULL); astr = bson_string_new(NULL); for (_i = 0; _i < _l; _i++) { _v = *(_b + _i); if ((_i % 16) == 0) { bson_string_append_printf(str, "%05x: ", _i); } bson_string_append_printf(str, " %02x", _v); if (isprint(_v)) { bson_string_append_printf(astr, " %c", _v); } else { bson_string_append(astr, " ."); } if ((_i % 16) == 15) { mongoc_log(MONGOC_LOG_LEVEL_TRACE, domain, "%s %s", str->str, astr->str); bson_string_truncate(str, 0); bson_string_truncate(astr, 0); } else if ((_i % 16) == 7) { bson_string_append(str, " "); bson_string_append(astr, " "); } } if (_i != 16) { mongoc_log(MONGOC_LOG_LEVEL_TRACE, domain, "%-56s %s", str->str, astr->str); } bson_string_free(str, true); bson_string_free(astr, true); } void mongoc_log_trace_iovec (const char *domain, const mongoc_iovec_t *_iov, size_t _iovcnt) { bson_string_t *str, *astr; const char *_b; unsigned _i = 0; unsigned _j = 0; unsigned _k = 0; size_t _l = 0; uint8_t _v; #ifdef MONGOC_TRACE if (!gLogTrace) { return; } #endif for (_i = 0; _i < _iovcnt; _i++) { _l += _iov[_i].iov_len; } _i = 0; str = bson_string_new(NULL); astr = bson_string_new(NULL); for (_j = 0; _j < _iovcnt; _j++) { _b = (char *)_iov[_j].iov_base; _l = _iov[_j].iov_len; for (_k = 0; _k < _l; _k++, _i++) { _v = *(_b + _k); if ((_i % 16) == 0) { bson_string_append_printf(str, "%05x: ", _i); } bson_string_append_printf(str, " %02x", _v); if (isprint(_v)) { bson_string_append_printf(astr, " %c", _v); } else { bson_string_append(astr, " ."); } if ((_i % 16) == 15) { mongoc_log(MONGOC_LOG_LEVEL_TRACE, domain, "%s %s", str->str, astr->str); bson_string_truncate(str, 0); bson_string_truncate(astr, 0); } else if ((_i % 16) == 7) { bson_string_append(str, " "); bson_string_append(astr, " "); } } } if (_i != 16) { mongoc_log(MONGOC_LOG_LEVEL_TRACE, domain, "%-56s %s", str->str, astr->str); } bson_string_free(str, true); bson_string_free(astr, true); } libmongoc-1.3.1/src/mongoc/mongoc-log.h000066400000000000000000000073461264720626300177720ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_LOG_H #define MONGOC_LOG_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS #ifndef MONGOC_LOG_DOMAIN # define MONGOC_LOG_DOMAIN "mongoc" #endif #define MONGOC_ERROR(...) mongoc_log(MONGOC_LOG_LEVEL_ERROR, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_CRITICAL(...) mongoc_log(MONGOC_LOG_LEVEL_CRITICAL, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_WARNING(...) mongoc_log(MONGOC_LOG_LEVEL_WARNING, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_MESSAGE(...) mongoc_log(MONGOC_LOG_LEVEL_MESSAGE, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_INFO(...) mongoc_log(MONGOC_LOG_LEVEL_INFO, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_DEBUG(...) mongoc_log(MONGOC_LOG_LEVEL_DEBUG, MONGOC_LOG_DOMAIN, __VA_ARGS__) typedef enum { MONGOC_LOG_LEVEL_ERROR, MONGOC_LOG_LEVEL_CRITICAL, MONGOC_LOG_LEVEL_WARNING, MONGOC_LOG_LEVEL_MESSAGE, MONGOC_LOG_LEVEL_INFO, MONGOC_LOG_LEVEL_DEBUG, MONGOC_LOG_LEVEL_TRACE, } mongoc_log_level_t; /** * mongoc_log_func_t: * @log_level: The level of the log message. * @log_domain: The domain of the log message, such as "client". * @message: The message generated. * @user_data: User data provided to mongoc_log_set_handler(). * * This function prototype can be used to set a custom log handler for the * libmongoc library. This is useful if you would like to show them in a * user interface or alternate storage. */ typedef void (*mongoc_log_func_t) (mongoc_log_level_t log_level, const char *log_domain, const char *message, void *user_data); /** * mongoc_log_set_handler: * @log_func: A function to handle log messages. * @user_data: User data for @log_func. * * Sets the function to be called to handle logging. */ void mongoc_log_set_handler (mongoc_log_func_t log_func, void *user_data); /** * mongoc_log: * @log_level: The log level. * @log_domain: The log domain (such as "client"). * @format: The format string for the log message. * * Logs a message using the currently configured logger. * * This method will hold a logging lock to prevent concurrent calls to the * logging infrastructure. It is important that your configured log function * does not re-enter the logging system or deadlock will occur. * */ void mongoc_log (mongoc_log_level_t log_level, const char *log_domain, const char *format, ...) BSON_GNUC_PRINTF(3, 4); void mongoc_log_default_handler (mongoc_log_level_t log_level, const char *log_domain, const char *message, void *user_data); /** * mongoc_log_level_str: * @log_level: The log level. * * Returns: The string representation of log_level */ const char * mongoc_log_level_str (mongoc_log_level_t log_level); BSON_END_DECLS #endif /* MONGOC_LOG_H */ libmongoc-1.3.1/src/mongoc/mongoc-matcher-op-private.h000066400000000000000000000101551264720626300227100ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_MATCHER_OP_PRIVATE_H #define MONGOC_MATCHER_OP_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef union _mongoc_matcher_op_t mongoc_matcher_op_t; typedef struct _mongoc_matcher_op_base_t mongoc_matcher_op_base_t; typedef struct _mongoc_matcher_op_logical_t mongoc_matcher_op_logical_t; typedef struct _mongoc_matcher_op_compare_t mongoc_matcher_op_compare_t; typedef struct _mongoc_matcher_op_exists_t mongoc_matcher_op_exists_t; typedef struct _mongoc_matcher_op_type_t mongoc_matcher_op_type_t; typedef struct _mongoc_matcher_op_not_t mongoc_matcher_op_not_t; typedef enum { MONGOC_MATCHER_OPCODE_EQ, MONGOC_MATCHER_OPCODE_GT, MONGOC_MATCHER_OPCODE_GTE, MONGOC_MATCHER_OPCODE_IN, MONGOC_MATCHER_OPCODE_LT, MONGOC_MATCHER_OPCODE_LTE, MONGOC_MATCHER_OPCODE_NE, MONGOC_MATCHER_OPCODE_NIN, MONGOC_MATCHER_OPCODE_OR, MONGOC_MATCHER_OPCODE_AND, MONGOC_MATCHER_OPCODE_NOT, MONGOC_MATCHER_OPCODE_NOR, MONGOC_MATCHER_OPCODE_EXISTS, MONGOC_MATCHER_OPCODE_TYPE, } mongoc_matcher_opcode_t; struct _mongoc_matcher_op_base_t { mongoc_matcher_opcode_t opcode; }; struct _mongoc_matcher_op_logical_t { mongoc_matcher_op_base_t base; mongoc_matcher_op_t *left; mongoc_matcher_op_t *right; }; struct _mongoc_matcher_op_compare_t { mongoc_matcher_op_base_t base; char *path; bson_iter_t iter; }; struct _mongoc_matcher_op_exists_t { mongoc_matcher_op_base_t base; char *path; bool exists; }; struct _mongoc_matcher_op_type_t { mongoc_matcher_op_base_t base; bson_type_t type; char *path; }; struct _mongoc_matcher_op_not_t { mongoc_matcher_op_base_t base; mongoc_matcher_op_t *child; char *path; }; union _mongoc_matcher_op_t { mongoc_matcher_op_base_t base; mongoc_matcher_op_logical_t logical; mongoc_matcher_op_compare_t compare; mongoc_matcher_op_exists_t exists; mongoc_matcher_op_type_t type; mongoc_matcher_op_not_t not_; }; mongoc_matcher_op_t *_mongoc_matcher_op_logical_new (mongoc_matcher_opcode_t opcode, mongoc_matcher_op_t *left, mongoc_matcher_op_t *right); mongoc_matcher_op_t *_mongoc_matcher_op_compare_new (mongoc_matcher_opcode_t opcode, const char *path, const bson_iter_t *iter); mongoc_matcher_op_t *_mongoc_matcher_op_exists_new (const char *path, bool exists); mongoc_matcher_op_t *_mongoc_matcher_op_type_new (const char *path, bson_type_t type); mongoc_matcher_op_t *_mongoc_matcher_op_not_new (const char *path, mongoc_matcher_op_t *child); bool _mongoc_matcher_op_match (mongoc_matcher_op_t *op, const bson_t *bson); void _mongoc_matcher_op_destroy (mongoc_matcher_op_t *op); void _mongoc_matcher_op_to_bson (mongoc_matcher_op_t *op, bson_t *bson); BSON_END_DECLS #endif /* MONGOC_MATCHER_OP_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-matcher-op.c000066400000000000000000001025771264720626300212450ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-log.h" #include "mongoc-matcher-op-private.h" #include "mongoc-util-private.h" /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_exists_new -- * * Create a new op for checking {$exists: bool}. * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_exists_new (const char *path, /* IN */ bool exists) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (path); op = (mongoc_matcher_op_t *)bson_malloc0 (sizeof *op); op->exists.base.opcode = MONGOC_MATCHER_OPCODE_EXISTS; op->exists.path = bson_strdup (path); op->exists.exists = exists; return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_type_new -- * * Create a new op for checking {$type: int}. * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_type_new (const char *path, /* IN */ bson_type_t type) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (path); BSON_ASSERT (type); op = (mongoc_matcher_op_t *)bson_malloc0 (sizeof *op); op->type.base.opcode = MONGOC_MATCHER_OPCODE_TYPE; op->type.path = bson_strdup (path); op->type.type = type; return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_logical_new -- * * Create a new op for checking any of: * * {$or: []} * {$nor: []} * {$and: []} * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_logical_new (mongoc_matcher_opcode_t opcode, /* IN */ mongoc_matcher_op_t *left, /* IN */ mongoc_matcher_op_t *right) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (left); BSON_ASSERT ((opcode >= MONGOC_MATCHER_OPCODE_OR) && (opcode <= MONGOC_MATCHER_OPCODE_NOR)); op = (mongoc_matcher_op_t *)bson_malloc0 (sizeof *op); op->logical.base.opcode = opcode; op->logical.left = left; op->logical.right = right; return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_compare_new -- * * Create a new op for checking any of: * * {"abc": "def"} * {$gt: {...} * {$gte: {...} * {$lt: {...} * {$lte: {...} * {$ne: {...} * {$in: [...]} * {$nin: [...]} * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_compare_new (mongoc_matcher_opcode_t opcode, /* IN */ const char *path, /* IN */ const bson_iter_t *iter) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (path); BSON_ASSERT (iter); op = (mongoc_matcher_op_t *)bson_malloc0 (sizeof *op); op->compare.base.opcode = opcode; op->compare.path = bson_strdup (path); memcpy (&op->compare.iter, iter, sizeof *iter); return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_not_new -- * * Create a new op for checking {$not: {...}} * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_not_new (const char *path, /* IN */ mongoc_matcher_op_t *child) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (path); BSON_ASSERT (child); op = (mongoc_matcher_op_t *)bson_malloc0 (sizeof *op); op->not_.base.opcode = MONGOC_MATCHER_OPCODE_NOT; op->not_.path = bson_strdup (path); op->not_.child = child; return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_destroy -- * * Free a mongoc_matcher_op_t structure and all children structures. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void _mongoc_matcher_op_destroy (mongoc_matcher_op_t *op) /* IN */ { BSON_ASSERT (op); switch (op->base.opcode) { case MONGOC_MATCHER_OPCODE_EQ: case MONGOC_MATCHER_OPCODE_GT: case MONGOC_MATCHER_OPCODE_GTE: case MONGOC_MATCHER_OPCODE_IN: case MONGOC_MATCHER_OPCODE_LT: case MONGOC_MATCHER_OPCODE_LTE: case MONGOC_MATCHER_OPCODE_NE: case MONGOC_MATCHER_OPCODE_NIN: bson_free (op->compare.path); break; case MONGOC_MATCHER_OPCODE_OR: case MONGOC_MATCHER_OPCODE_AND: case MONGOC_MATCHER_OPCODE_NOR: if (op->logical.left) _mongoc_matcher_op_destroy (op->logical.left); if (op->logical.right) _mongoc_matcher_op_destroy (op->logical.right); break; case MONGOC_MATCHER_OPCODE_NOT: _mongoc_matcher_op_destroy (op->not_.child); bson_free (op->not_.path); break; case MONGOC_MATCHER_OPCODE_EXISTS: bson_free (op->exists.path); break; case MONGOC_MATCHER_OPCODE_TYPE: bson_free (op->type.path); break; default: break; } bson_free (op); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_exists_match -- * * Checks to see if @bson matches @exists requirements. The * {$exists: bool} query can be either true or fase so we must * handle false as "not exists". * * Returns: * true if the field exists and the spec expected it. * true if the field does not exist and the spec expected it to not * exist. * Otherwise, false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_exists_match (mongoc_matcher_op_exists_t *exists, /* IN */ const bson_t *bson) /* IN */ { bson_iter_t iter; bson_iter_t desc; bool found; BSON_ASSERT (exists); BSON_ASSERT (bson); found = (bson_iter_init (&iter, bson) && bson_iter_find_descendant (&iter, exists->path, &desc)); return (found == exists->exists); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_type_match -- * * Checks if @bson matches the {$type: ...} op. * * Returns: * true if the requested field was found and the type matched * the requested type. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_type_match (mongoc_matcher_op_type_t *type, /* IN */ const bson_t *bson) /* IN */ { bson_iter_t iter; bson_iter_t desc; BSON_ASSERT (type); BSON_ASSERT (bson); if (bson_iter_init (&iter, bson) && bson_iter_find_descendant (&iter, type->path, &desc)) { return (bson_iter_type (&iter) == type->type); } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_not_match -- * * Checks if the {$not: ...} expression matches by negating the * child expression. * * Returns: * true if the child expression returned false. * Otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_not_match (mongoc_matcher_op_not_t *not_, /* IN */ const bson_t *bson) /* IN */ { BSON_ASSERT (not_); BSON_ASSERT (bson); return !_mongoc_matcher_op_match (not_->child, bson); } #define _TYPE_CODE(l, r) ((((int)(l)) << 8) | ((int)(r))) #define _NATIVE_COMPARE(op, t1, t2) \ (bson_iter##t2(iter) op bson_iter##t1(compare_iter)) #define _EQ_COMPARE(t1, t2) _NATIVE_COMPARE(==, t1, t2) #define _NE_COMPARE(t1, t2) _NATIVE_COMPARE(!=, t1, t2) #define _GT_COMPARE(t1, t2) _NATIVE_COMPARE(>, t1, t2) #define _GTE_COMPARE(t1, t2) _NATIVE_COMPARE(>=, t1, t2) #define _LT_COMPARE(t1, t2) _NATIVE_COMPARE(<, t1, t2) #define _LTE_COMPARE(t1, t2) _NATIVE_COMPARE(<=, t1, t2) /* *-------------------------------------------------------------------------- * * _mongoc_matcher_iter_eq_match -- * * Performs equality match for all types on either left or right * side of the equation. * * We try to default to what the compiler would do for comparing * things like integers. Therefore, we just have MACRO'tized * everything so that the compiler sees the native values. (Such * as (double == int64). * * The _TYPE_CODE() stuff allows us to shove the type of the left * and the right into a single integer and then do a jump table * with a switch/case for all our supported types. * * I imagine a bunch more of these will need to be added, so feel * free to submit patches. * * Returns: * true if the equality match succeeded. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_iter_eq_match (bson_iter_t *compare_iter, /* IN */ bson_iter_t *iter) /* IN */ { int code; BSON_ASSERT (compare_iter); BSON_ASSERT (iter); code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _EQ_COMPARE (_double, _double); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _EQ_COMPARE (_double, _bool); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _EQ_COMPARE (_double, _int32); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _EQ_COMPARE (_double, _int64); /* UTF8 on Left Side */ case _TYPE_CODE(BSON_TYPE_UTF8, BSON_TYPE_UTF8): { uint32_t llen; uint32_t rlen; const char *lstr; const char *rstr; lstr = bson_iter_utf8 (compare_iter, &llen); rstr = bson_iter_utf8 (iter, &rlen); return ((llen == rlen) && (0 == memcmp (lstr, rstr, llen))); } /* Int32 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _EQ_COMPARE (_int32, _double); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_BOOL): return _EQ_COMPARE (_int32, _bool); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT32): return _EQ_COMPARE (_int32, _int32); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT64): return _EQ_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _EQ_COMPARE (_int64, _double); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_BOOL): return _EQ_COMPARE (_int64, _bool); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT32): return _EQ_COMPARE (_int64, _int32); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT64): return _EQ_COMPARE (_int64, _int64); /* Null on Left Side */ case _TYPE_CODE(BSON_TYPE_NULL, BSON_TYPE_NULL): case _TYPE_CODE(BSON_TYPE_NULL, BSON_TYPE_UNDEFINED): return true; case _TYPE_CODE (BSON_TYPE_ARRAY, BSON_TYPE_ARRAY): { bson_iter_t left_array; bson_iter_t right_array; bson_iter_recurse (compare_iter, &left_array); bson_iter_recurse (iter, &right_array); while (true) { bool left_has_next = bson_iter_next (&left_array); bool right_has_next = bson_iter_next (&right_array); if (left_has_next != right_has_next) { /* different lengths */ return false; } if (!left_has_next) { /* finished */ return true; } if (!_mongoc_matcher_iter_eq_match (&left_array, &right_array)) { return false; } } } case _TYPE_CODE (BSON_TYPE_DOCUMENT, BSON_TYPE_DOCUMENT): { uint32_t llen; uint32_t rlen; const uint8_t *ldoc; const uint8_t *rdoc; bson_iter_document (compare_iter, &llen, &ldoc); bson_iter_document (iter, &rlen, &rdoc); return ((llen == rlen) && (0 == memcmp (ldoc, rdoc, llen))); } default: return false; } } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_eq_match -- * * Performs equality match for all types on either left or right * side of the equation. * * Returns: * true if the equality match succeeded. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_eq_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { BSON_ASSERT (compare); BSON_ASSERT (iter); return _mongoc_matcher_iter_eq_match (&compare->iter, iter); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_gt_match -- * * Perform {$gt: ...} match using @compare. * * In general, we try to default to what the compiler would do * for comparison between different types. * * Returns: * true if the document field was > the spec value. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_gt_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { int code; bson_iter_t *compare_iter = &compare->iter; BSON_ASSERT (compare); BSON_ASSERT (iter); code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _GT_COMPARE (_double, _double); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _GT_COMPARE (_double, _bool); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _GT_COMPARE (_double, _int32); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _GT_COMPARE (_double, _int64); /* Int32 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _GT_COMPARE (_int32, _double); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_BOOL): return _GT_COMPARE (_int32, _bool); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT32): return _GT_COMPARE (_int32, _int32); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT64): return _GT_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _GT_COMPARE (_int64, _double); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_BOOL): return _GT_COMPARE (_int64, _bool); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT32): return _GT_COMPARE (_int64, _int32); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT64): return _GT_COMPARE (_int64, _int64); default: MONGOC_WARNING ("Implement for (Type(%d) > Type(%d))", bson_iter_type (compare_iter), bson_iter_type (iter)); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_gte_match -- * * Perform a match of {"path": {"$gte": value}}. * * Returns: * true if the the spec matches, otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_gte_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { bson_iter_t *compare_iter; int code; BSON_ASSERT (compare); BSON_ASSERT (iter); compare_iter = &compare->iter; code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _GTE_COMPARE (_double, _double); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _GTE_COMPARE (_double, _bool); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _GTE_COMPARE (_double, _int32); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _GTE_COMPARE (_double, _int64); /* Int32 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _GTE_COMPARE (_int32, _double); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_BOOL): return _GTE_COMPARE (_int32, _bool); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT32): return _GTE_COMPARE (_int32, _int32); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT64): return _GTE_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _GTE_COMPARE (_int64, _double); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_BOOL): return _GTE_COMPARE (_int64, _bool); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT32): return _GTE_COMPARE (_int64, _int32); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT64): return _GTE_COMPARE (_int64, _int64); default: MONGOC_WARNING ("Implement for (Type(%d) >= Type(%d))", bson_iter_type (compare_iter), bson_iter_type (iter)); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_in_match -- * * Checks the spec {"path": {"$in": [value1, value2, ...]}}. * * Returns: * true if the spec matched, otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_in_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { mongoc_matcher_op_compare_t op; op.base.opcode = MONGOC_MATCHER_OPCODE_EQ; op.path = compare->path; if (!BSON_ITER_HOLDS_ARRAY (&compare->iter) || !bson_iter_recurse (&compare->iter, &op.iter)) { return false; } while (bson_iter_next (&op.iter)) { if (_mongoc_matcher_op_eq_match (&op, iter)) { return true; } } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_lt_match -- * * Perform a {"path": "$lt": {value}} match. * * Returns: * true if the spec matched, otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_lt_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { bson_iter_t *compare_iter; int code; BSON_ASSERT (compare); BSON_ASSERT (iter); compare_iter = &compare->iter; code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _LT_COMPARE (_double, _double); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _LT_COMPARE (_double, _bool); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _LT_COMPARE (_double, _int32); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _LT_COMPARE (_double, _int64); /* Int32 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _LT_COMPARE (_int32, _double); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_BOOL): return _LT_COMPARE (_int32, _bool); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT32): return _LT_COMPARE (_int32, _int32); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT64): return _LT_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _LT_COMPARE (_int64, _double); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_BOOL): return _LT_COMPARE (_int64, _bool); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT32): return _LT_COMPARE (_int64, _int32); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT64): return _LT_COMPARE (_int64, _int64); default: MONGOC_WARNING ("Implement for (Type(%d) < Type(%d))", bson_iter_type (compare_iter), bson_iter_type (iter)); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_lte_match -- * * Perform a {"$path": {"$lte": value}} match. * * Returns: * true if the spec matched, otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_lte_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { bson_iter_t *compare_iter; int code; BSON_ASSERT (compare); BSON_ASSERT (iter); compare_iter = &compare->iter; code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _LTE_COMPARE (_double, _double); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _LTE_COMPARE (_double, _bool); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _LTE_COMPARE (_double, _int32); case _TYPE_CODE(BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _LTE_COMPARE (_double, _int64); /* Int32 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _LTE_COMPARE (_int32, _double); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_BOOL): return _LTE_COMPARE (_int32, _bool); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT32): return _LTE_COMPARE (_int32, _int32); case _TYPE_CODE(BSON_TYPE_INT32, BSON_TYPE_INT64): return _LTE_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _LTE_COMPARE (_int64, _double); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_BOOL): return _LTE_COMPARE (_int64, _bool); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT32): return _LTE_COMPARE (_int64, _int32); case _TYPE_CODE(BSON_TYPE_INT64, BSON_TYPE_INT64): return _LTE_COMPARE (_int64, _int64); default: MONGOC_WARNING ("Implement for (Type(%d) <= Type(%d))", bson_iter_type (compare_iter), bson_iter_type (iter)); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_ne_match -- * * Perform a {"path": {"$ne": value}} match. * * Returns: * true if the field "path" was not found or the value is not-equal * to value. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_ne_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { return !_mongoc_matcher_op_eq_match (compare, iter); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_nin_match -- * * Perform a {"path": {"$nin": value}} match. * * Returns: * true if value was not found in the array at "path". * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_nin_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { return !_mongoc_matcher_op_in_match (compare, iter); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_compare_match -- * * Dispatch function for mongoc_matcher_op_compare_t operations * to perform a match. * * Returns: * Opcode dependent. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_compare_match (mongoc_matcher_op_compare_t *compare, /* IN */ const bson_t *bson) /* IN */ { bson_iter_t tmp; bson_iter_t iter; BSON_ASSERT (compare); BSON_ASSERT (bson); if (strchr (compare->path, '.')) { if (!bson_iter_init (&tmp, bson) || !bson_iter_find_descendant (&tmp, compare->path, &iter)) { return false; } } else if (!bson_iter_init_find (&iter, bson, compare->path)) { return false; } switch ((int)compare->base.opcode) { case MONGOC_MATCHER_OPCODE_EQ: return _mongoc_matcher_op_eq_match (compare, &iter); case MONGOC_MATCHER_OPCODE_GT: return _mongoc_matcher_op_gt_match (compare, &iter); case MONGOC_MATCHER_OPCODE_GTE: return _mongoc_matcher_op_gte_match (compare, &iter); case MONGOC_MATCHER_OPCODE_IN: return _mongoc_matcher_op_in_match (compare, &iter); case MONGOC_MATCHER_OPCODE_LT: return _mongoc_matcher_op_lt_match (compare, &iter); case MONGOC_MATCHER_OPCODE_LTE: return _mongoc_matcher_op_lte_match (compare, &iter); case MONGOC_MATCHER_OPCODE_NE: return _mongoc_matcher_op_ne_match (compare, &iter); case MONGOC_MATCHER_OPCODE_NIN: return _mongoc_matcher_op_nin_match (compare, &iter); default: BSON_ASSERT (false); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_logical_match -- * * Dispatch function for mongoc_matcher_op_logical_t operations * to perform a match. * * Returns: * Opcode specific. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_logical_match (mongoc_matcher_op_logical_t *logical, /* IN */ const bson_t *bson) /* IN */ { BSON_ASSERT (logical); BSON_ASSERT (bson); switch ((int)logical->base.opcode) { case MONGOC_MATCHER_OPCODE_OR: return (_mongoc_matcher_op_match (logical->left, bson) || _mongoc_matcher_op_match (logical->right, bson)); case MONGOC_MATCHER_OPCODE_AND: return (_mongoc_matcher_op_match (logical->left, bson) && _mongoc_matcher_op_match (logical->right, bson)); case MONGOC_MATCHER_OPCODE_NOR: return !(_mongoc_matcher_op_match (logical->left, bson) || _mongoc_matcher_op_match (logical->right, bson)); default: BSON_ASSERT (false); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_match -- * * Dispatch function for all operation types to perform a match. * * Returns: * Opcode specific. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool _mongoc_matcher_op_match (mongoc_matcher_op_t *op, /* IN */ const bson_t *bson) /* IN */ { BSON_ASSERT (op); BSON_ASSERT (bson); switch (op->base.opcode) { case MONGOC_MATCHER_OPCODE_EQ: case MONGOC_MATCHER_OPCODE_GT: case MONGOC_MATCHER_OPCODE_GTE: case MONGOC_MATCHER_OPCODE_IN: case MONGOC_MATCHER_OPCODE_LT: case MONGOC_MATCHER_OPCODE_LTE: case MONGOC_MATCHER_OPCODE_NE: case MONGOC_MATCHER_OPCODE_NIN: return _mongoc_matcher_op_compare_match (&op->compare, bson); case MONGOC_MATCHER_OPCODE_OR: case MONGOC_MATCHER_OPCODE_AND: case MONGOC_MATCHER_OPCODE_NOR: return _mongoc_matcher_op_logical_match (&op->logical, bson); case MONGOC_MATCHER_OPCODE_NOT: return _mongoc_matcher_op_not_match (&op->not_, bson); case MONGOC_MATCHER_OPCODE_EXISTS: return _mongoc_matcher_op_exists_match (&op->exists, bson); case MONGOC_MATCHER_OPCODE_TYPE: return _mongoc_matcher_op_type_match (&op->type, bson); default: break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_to_bson -- * * Convert the optree specified by @op to a bson document similar * to what the query would have been. This is not perfectly the * same, and so should not be used as such. * * Returns: * None. * * Side effects: * @bson is appended to, and therefore must be initialized before * calling this function. * *-------------------------------------------------------------------------- */ void _mongoc_matcher_op_to_bson (mongoc_matcher_op_t *op, /* IN */ bson_t *bson) /* IN */ { const char *str; bson_t child; bson_t child2; BSON_ASSERT (op); BSON_ASSERT (bson); switch (op->base.opcode) { case MONGOC_MATCHER_OPCODE_EQ: _ignore_value(bson_append_iter (bson, op->compare.path, -1, &op->compare.iter)); break; case MONGOC_MATCHER_OPCODE_GT: case MONGOC_MATCHER_OPCODE_GTE: case MONGOC_MATCHER_OPCODE_IN: case MONGOC_MATCHER_OPCODE_LT: case MONGOC_MATCHER_OPCODE_LTE: case MONGOC_MATCHER_OPCODE_NE: case MONGOC_MATCHER_OPCODE_NIN: switch ((int)op->base.opcode) { case MONGOC_MATCHER_OPCODE_GT: str = "$gt"; break; case MONGOC_MATCHER_OPCODE_GTE: str = "$gte"; break; case MONGOC_MATCHER_OPCODE_IN: str = "$in"; break; case MONGOC_MATCHER_OPCODE_LT: str = "$lt"; break; case MONGOC_MATCHER_OPCODE_LTE: str = "$lte"; break; case MONGOC_MATCHER_OPCODE_NE: str = "$ne"; break; case MONGOC_MATCHER_OPCODE_NIN: str = "$nin"; break; default: str = "???"; break; } if (bson_append_document_begin (bson, op->compare.path, -1, &child)) { _ignore_value (bson_append_iter (&child, str, -1, &op->compare.iter)); bson_append_document_end (bson, &child); } break; case MONGOC_MATCHER_OPCODE_OR: case MONGOC_MATCHER_OPCODE_AND: case MONGOC_MATCHER_OPCODE_NOR: if (op->base.opcode == MONGOC_MATCHER_OPCODE_OR) { str = "$or"; } else if (op->base.opcode == MONGOC_MATCHER_OPCODE_AND) { str = "$and"; } else if (op->base.opcode == MONGOC_MATCHER_OPCODE_NOR) { str = "$nor"; } else { BSON_ASSERT (false); str = NULL; } bson_append_array_begin (bson, str, -1, &child); bson_append_document_begin (&child, "0", 1, &child2); _mongoc_matcher_op_to_bson (op->logical.left, &child2); bson_append_document_end (&child, &child2); if (op->logical.right) { bson_append_document_begin (&child, "1", 1, &child2); _mongoc_matcher_op_to_bson (op->logical.right, &child2); bson_append_document_end (&child, &child2); } bson_append_array_end (bson, &child); break; case MONGOC_MATCHER_OPCODE_NOT: bson_append_document_begin (bson, op->not_.path, -1, &child); bson_append_document_begin (&child, "$not", 4, &child2); _mongoc_matcher_op_to_bson (op->not_.child, &child2); bson_append_document_end (&child, &child2); bson_append_document_end (bson, &child); break; case MONGOC_MATCHER_OPCODE_EXISTS: BSON_APPEND_BOOL (bson, "$exists", op->exists.exists); break; case MONGOC_MATCHER_OPCODE_TYPE: BSON_APPEND_INT32 (bson, "$type", (int)op->type.type); break; default: BSON_ASSERT (false); break; } } libmongoc-1.3.1/src/mongoc/mongoc-matcher-private.h000066400000000000000000000017741264720626300223030ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_MATCHER_PRIVATE_H #define MONGOC_MATCHER_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-matcher-op-private.h" BSON_BEGIN_DECLS struct _mongoc_matcher_t { bson_t query; mongoc_matcher_op_t *optree; }; BSON_END_DECLS #endif /* MONGOC_MATCHER_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-matcher.c000066400000000000000000000274431264720626300206270ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-error.h" #include "mongoc-matcher.h" #include "mongoc-matcher-private.h" #include "mongoc-matcher-op-private.h" static mongoc_matcher_op_t * _mongoc_matcher_parse_logical (mongoc_matcher_opcode_t opcode, bson_iter_t *iter, bool is_root, bson_error_t *error); /* *-------------------------------------------------------------------------- * * _mongoc_matcher_parse_compare -- * * Parse a compare spec such as $gt or $in. * * See the following link for more information. * * http://docs.mongodb.org/manual/reference/operator/query/ * * Returns: * A newly allocated mongoc_matcher_op_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ static mongoc_matcher_op_t * _mongoc_matcher_parse_compare (bson_iter_t *iter, /* IN */ const char *path, /* IN */ bson_error_t *error) /* OUT */ { const char * key; mongoc_matcher_op_t * op = NULL, * op_child; bson_iter_t child; BSON_ASSERT (iter); BSON_ASSERT (path); if (bson_iter_type (iter) == BSON_TYPE_DOCUMENT) { if (!bson_iter_recurse (iter, &child) || !bson_iter_next (&child)) { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Document contains no operations."); return NULL; } key = bson_iter_key (&child); if (key[0] != '$') { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_EQ, path, iter); } else if (strcmp(key, "$not") == 0) { if (!(op_child = _mongoc_matcher_parse_compare (&child, path, error))) { return NULL; } op = _mongoc_matcher_op_not_new (path, op_child); } else if (strcmp(key, "$gt") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_GT, path, &child); } else if (strcmp(key, "$gte") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_GTE, path, &child); } else if (strcmp(key, "$in") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_IN, path, &child); } else if (strcmp(key, "$lt") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_LT, path, &child); } else if (strcmp(key, "$lte") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_LTE, path, &child); } else if (strcmp(key, "$ne") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_NE, path, &child); } else if (strcmp(key, "$nin") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_NIN, path, &child); } else if (strcmp(key, "$exists") == 0) { op = _mongoc_matcher_op_exists_new (path, bson_iter_bool (&child)); } else if (strcmp(key, "$type") == 0) { op = _mongoc_matcher_op_type_new (path, bson_iter_type (&child)); } else { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Invalid operator \"%s\"", key); return NULL; } } else { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_EQ, path, iter); } BSON_ASSERT (op); return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_parse -- * * Parse a query spec observed by the current key of @iter. * * Returns: * A newly allocated mongoc_matcher_op_t if successful; otherwise * NULL an @error is set. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ static mongoc_matcher_op_t * _mongoc_matcher_parse (bson_iter_t *iter, /* IN */ bson_error_t *error) /* OUT */ { bson_iter_t child; const char *key; BSON_ASSERT (iter); key = bson_iter_key (iter); if (*key != '$') { return _mongoc_matcher_parse_compare (iter, key, error); } else { BSON_ASSERT (bson_iter_type(iter) == BSON_TYPE_ARRAY); if (!bson_iter_recurse (iter, &child)) { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Invalid value for operator \"%s\"", key); return NULL; } if (strcmp (key, "$or") == 0) { return _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_OR, &child, false, error); } else if (strcmp(key, "$and") == 0) { return _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_AND, &child, false, error); } else if (strcmp(key, "$nor") == 0) { return _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_NOR, &child, false, error); } } bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Invalid operator \"%s\"", key); return NULL; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_parse_logical -- * * Parse a query spec containing a logical operator such as * $or, $and, $not, and $nor. * * See the following link for more information. * * http://docs.mongodb.org/manual/reference/operator/query/ * * Returns: * A newly allocated mongoc_matcher_op_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ static mongoc_matcher_op_t * _mongoc_matcher_parse_logical (mongoc_matcher_opcode_t opcode, /* IN */ bson_iter_t *iter, /* IN */ bool is_root, /* IN */ bson_error_t *error) /* OUT */ { mongoc_matcher_op_t *left; mongoc_matcher_op_t *right; mongoc_matcher_op_t *more; mongoc_matcher_op_t *more_wrap; bson_iter_t child; BSON_ASSERT (opcode); BSON_ASSERT (iter); BSON_ASSERT (iter); if (!bson_iter_next (iter)) { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Invalid logical operator."); return NULL; } if (is_root) { if (!(left = _mongoc_matcher_parse (iter, error))) { return NULL; } } else { if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Expected document in value."); return NULL; } bson_iter_recurse (iter, &child); bson_iter_next (&child); if (!(left = _mongoc_matcher_parse (&child, error))) { return NULL; } } if (!bson_iter_next (iter)) { return left; } if (is_root) { if (!(right = _mongoc_matcher_parse (iter, error))) { return NULL; } } else { if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Expected document in value."); return NULL; } bson_iter_recurse (iter, &child); bson_iter_next (&child); if (!(right = _mongoc_matcher_parse (&child, error))) { return NULL; } } more = _mongoc_matcher_parse_logical (opcode, iter, is_root, error); if (more) { more_wrap = _mongoc_matcher_op_logical_new (opcode, right, more); return _mongoc_matcher_op_logical_new (opcode, left, more_wrap); } return _mongoc_matcher_op_logical_new (opcode, left, right); } /* *-------------------------------------------------------------------------- * * mongoc_matcher_new -- * * Create a new mongoc_matcher_t using the query specification * provided in @query. * * This will build an operation tree that can be applied to arbitrary * bson documents using mongoc_matcher_match(). * * Returns: * A newly allocated mongoc_matcher_t if successful; otherwise NULL * and @error is set. * * The mongoc_matcher_t should be freed with * mongoc_matcher_destroy(). * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ mongoc_matcher_t * mongoc_matcher_new (const bson_t *query, /* IN */ bson_error_t *error) /* OUT */ { mongoc_matcher_op_t *op; mongoc_matcher_t *matcher; bson_iter_t iter; BSON_ASSERT (query); matcher = (mongoc_matcher_t *)bson_malloc0 (sizeof *matcher); bson_copy_to (query, &matcher->query); if (!bson_iter_init (&iter, &matcher->query)) { goto failure; } if (!(op = _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_AND, &iter, true, error))) { goto failure; } matcher->optree = op; return matcher; failure: bson_destroy (&matcher->query); bson_free (matcher); return NULL; } /* *-------------------------------------------------------------------------- * * mongoc_matcher_match -- * * Checks to see if @bson matches the query specified when creating * @matcher. * * Returns: * TRUE if @bson matched the query, otherwise FALSE. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool mongoc_matcher_match (const mongoc_matcher_t *matcher, /* IN */ const bson_t *document) /* IN */ { BSON_ASSERT (matcher); BSON_ASSERT (matcher->optree); BSON_ASSERT (document); return _mongoc_matcher_op_match (matcher->optree, document); } /* *-------------------------------------------------------------------------- * * mongoc_matcher_destroy -- * * Release all resources associated with @matcher. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_matcher_destroy (mongoc_matcher_t *matcher) /* IN */ { BSON_ASSERT (matcher); _mongoc_matcher_op_destroy (matcher->optree); bson_destroy (&matcher->query); bson_free (matcher); } libmongoc-1.3.1/src/mongoc/mongoc-matcher.h000066400000000000000000000025161264720626300206260ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_MATCHER_H #define MONGOC_MATCHER_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef struct _mongoc_matcher_t mongoc_matcher_t; mongoc_matcher_t *mongoc_matcher_new (const bson_t *query, bson_error_t *error) BSON_GNUC_DEPRECATED; bool mongoc_matcher_match (const mongoc_matcher_t *matcher, const bson_t *document) BSON_GNUC_DEPRECATED; void mongoc_matcher_destroy (mongoc_matcher_t *matcher) BSON_GNUC_DEPRECATED; BSON_END_DECLS #endif /* MONGOC_MATCHER_H */ libmongoc-1.3.1/src/mongoc/mongoc-memcmp-private.h000066400000000000000000000022431264720626300221260ustar00rootroot00000000000000/* * Copyright 2015 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_MEMCMP_PRIVATE_H #define MONGOC_MEMCMP_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-config.h" /* WARNING: mongoc_memcmp() must be used to verify if two secret keys * are equal, in constant time. * It returns 0 if the keys are equal, and -1 if they differ. * This function is not designed for lexicographical comparisons. */ int mongoc_memcmp(const void * const b1_, const void * const b2_, size_t len); #endif /* MONGOC_MEMCMP_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-memcmp.c000066400000000000000000000036041264720626300204530ustar00rootroot00000000000000/* * Copyright (c) 2013-2015 * Frank Denis * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mongoc-memcmp-private.h" #ifdef MONGOC_HAVE_WEAK_SYMBOLS __attribute__((weak)) void _mongoc_dummy_symbol_to_prevent_memcmp_lto(const unsigned char *b1, const unsigned char *b2, const size_t len) { (void) b1; (void) b2; (void) len; } #endif /* See: http://doc.libsodium.org/helpers/index.html#constant-time-comparison */ int mongoc_memcmp(const void * const b1_, const void * const b2_, size_t len) { #ifdef MONGOC_HAVE_WEAK_SYMBOLS const unsigned char *b1 = (const unsigned char *) b1_; const unsigned char *b2 = (const unsigned char *) b2_; #else const volatile unsigned char *b1 = (const volatile unsigned char *) b1_; const volatile unsigned char *b2 = (const volatile unsigned char *) b2_; #endif size_t i; unsigned char d = (unsigned char) 0U; #if MONGOC_HAVE_WEAK_SYMBOLS _mongoc_dummy_symbol_to_prevent_memcmp_lto(b1, b2, len); #endif for (i = 0U; i < len; i++) { d |= b1[i] ^ b2[i]; } return (int) ((1 & ((d - 1) >> 8)) - 1); } libmongoc-1.3.1/src/mongoc/mongoc-opcode-private.h000066400000000000000000000014221264720626300221170ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_OPCODE_PRIVATE_H #define MONGOC_OPCODE_PRIVATE_H #include "mongoc-opcode.h" bool _mongoc_opcode_needs_primary(mongoc_opcode_t opcode); #endif /* MONGOC_OPCODE_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-opcode.c000066400000000000000000000033251264720626300204460ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-opcode-private.h" /* *-------------------------------------------------------------------------- * * _mongoc_opcode_needs_primary -- * * Returns true if this operation needs to run on a primary, * false if it does not. * * Returns: * true, false * * Side effects: * None * *-------------------------------------------------------------------------- */ bool _mongoc_opcode_needs_primary (mongoc_opcode_t opcode) { bool needs_primary = false; switch(opcode) { case MONGOC_OPCODE_KILL_CURSORS: case MONGOC_OPCODE_GET_MORE: case MONGOC_OPCODE_MSG: case MONGOC_OPCODE_REPLY: needs_primary = false; break; case MONGOC_OPCODE_QUERY: /* In some cases, queries may be run against secondaries. However, more information is needed to make that decision. Callers with access to read preferences and query flags may route queries to a secondary when appropriate */ case MONGOC_OPCODE_DELETE: case MONGOC_OPCODE_INSERT: case MONGOC_OPCODE_UPDATE: default: needs_primary = true; break; } return needs_primary; } libmongoc-1.3.1/src/mongoc/mongoc-opcode.h000066400000000000000000000022551264720626300204540ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_OPCODE_H #define MONGOC_OPCODE_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef enum { MONGOC_OPCODE_REPLY = 1, MONGOC_OPCODE_MSG = 1000, MONGOC_OPCODE_UPDATE = 2001, MONGOC_OPCODE_INSERT = 2002, MONGOC_OPCODE_QUERY = 2004, MONGOC_OPCODE_GET_MORE = 2005, MONGOC_OPCODE_DELETE = 2006, MONGOC_OPCODE_KILL_CURSORS = 2007, } mongoc_opcode_t; BSON_END_DECLS #endif /* MONGOC_OPCODE_H */ libmongoc-1.3.1/src/mongoc/mongoc-queue-private.h000066400000000000000000000032641264720626300220000ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_QUEUE_PRIVATE_H #define MONGOC_QUEUE_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-list-private.h" BSON_BEGIN_DECLS #define MONGOC_QUEUE_INITIALIZER {NULL,NULL} typedef struct _mongoc_queue_t mongoc_queue_t; typedef struct _mongoc_queue_item_t mongoc_queue_item_t; struct _mongoc_queue_t { mongoc_queue_item_t *head; mongoc_queue_item_t *tail; }; struct _mongoc_queue_item_t { mongoc_queue_item_t *next; void *data; }; void _mongoc_queue_init (mongoc_queue_t *queue); void *_mongoc_queue_pop_head (mongoc_queue_t *queue); void _mongoc_queue_push_head (mongoc_queue_t *queue, void *data); void _mongoc_queue_push_tail (mongoc_queue_t *queue, void *data); uint32_t _mongoc_queue_get_length (const mongoc_queue_t *queue); BSON_END_DECLS #endif /* MONGOC_QUEUE_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-queue.c000066400000000000000000000040751264720626300203240ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-queue-private.h" void _mongoc_queue_init (mongoc_queue_t *queue) { BSON_ASSERT (queue); memset (queue, 0, sizeof *queue); } void _mongoc_queue_push_head (mongoc_queue_t *queue, void *data) { mongoc_queue_item_t *item; BSON_ASSERT (queue); BSON_ASSERT (data); item = (mongoc_queue_item_t *)bson_malloc0(sizeof *item); item->next = queue->head; item->data = data; queue->head = item; if (!queue->tail) { queue->tail = item; } } void _mongoc_queue_push_tail (mongoc_queue_t *queue, void *data) { mongoc_queue_item_t *item; BSON_ASSERT (queue); BSON_ASSERT (data); item = (mongoc_queue_item_t *)bson_malloc0(sizeof *item); item->data = data; if (queue->tail) { queue->tail->next = item; } else { queue->head = item; } queue->tail = item; } void * _mongoc_queue_pop_head (mongoc_queue_t *queue) { mongoc_queue_item_t *item; void *data = NULL; BSON_ASSERT (queue); if ((item = queue->head)) { if (!item->next) { queue->tail = NULL; } queue->head = item->next; data = item->data; bson_free(item); } return data; } uint32_t _mongoc_queue_get_length (const mongoc_queue_t *queue) { mongoc_queue_item_t *item; uint32_t count = 0; BSON_ASSERT (queue); for (item = queue->head; item; item = item->next) { count++; } return count; } libmongoc-1.3.1/src/mongoc/mongoc-rand-private.h000066400000000000000000000017261264720626300216010ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #ifndef MONGOC_RAND_PRIVATE_H #define MONGOC_RAND_PRIVATE_H #include BSON_BEGIN_DECLS int _mongoc_rand_bytes(uint8_t * buf, int num); int _mongoc_pseudo_rand_bytes(uint8_t * buf, int num); BSON_END_DECLS #endif /* MONGOC_RAND_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-rand.c000066400000000000000000000022431264720626300201170ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-config.h" #ifdef MONGOC_ENABLE_SSL #include "mongoc-rand.h" #include "mongoc-rand-private.h" #include "mongoc.h" #include int _mongoc_rand_bytes(uint8_t * buf, int num) { return RAND_bytes(buf, num); } int _mongoc_pseudo_rand_bytes(uint8_t * buf, int num) { return RAND_pseudo_bytes(buf, num); } void mongoc_rand_seed(const void* buf, int num) { RAND_seed(buf, num); } void mongoc_rand_add(const void* buf, int num, double entropy) { RAND_add(buf, num, entropy); } int mongoc_rand_status(void) { return RAND_status(); } #endif libmongoc-1.3.1/src/mongoc/mongoc-rand.h000066400000000000000000000017371264720626300201330ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #ifndef MONGOC_RAND_H #define MONGOC_RAND_H #include BSON_BEGIN_DECLS void mongoc_rand_seed(const void* buf, int num); void mongoc_rand_add(const void* buf, int num, double entropy); int mongoc_rand_status(void); BSON_END_DECLS #endif /* MONGOC_RAND_H */ libmongoc-1.3.1/src/mongoc/mongoc-read-concern-private.h000066400000000000000000000021371264720626300232120ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_READ_CONCERN_PRIVATE_H #define MONGOC_READ_CONCERN_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-read-concern.h" BSON_BEGIN_DECLS struct _mongoc_read_concern_t { char *level; bool frozen; bson_t compiled; }; const bson_t *_mongoc_read_concern_get_bson (mongoc_read_concern_t *read_concern); BSON_END_DECLS #endif /* MONGOC_READ_CONCERN_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-read-concern.c000066400000000000000000000101651264720626300215350ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-log.h" #include "mongoc-read-concern.h" #include "mongoc-read-concern-private.h" static void _mongoc_read_concern_freeze (mongoc_read_concern_t *read_concern); /** * mongoc_read_concern_new: * * Create a new mongoc_read_concern_t. * * Returns: A newly allocated mongoc_read_concern_t. This should be freed * with mongoc_read_concern_destroy(). */ mongoc_read_concern_t * mongoc_read_concern_new (void) { mongoc_read_concern_t *read_concern; read_concern = (mongoc_read_concern_t *)bson_malloc0 (sizeof *read_concern); return read_concern; } mongoc_read_concern_t * mongoc_read_concern_copy (const mongoc_read_concern_t *read_concern) { mongoc_read_concern_t *ret = NULL; if (read_concern) { ret = mongoc_read_concern_new (); ret->level = bson_strdup (read_concern->level); } return ret; } /** * mongoc_read_concern_destroy: * @read_concern: A mongoc_read_concern_t. * * Releases a mongoc_read_concern_t and all associated memory. */ void mongoc_read_concern_destroy (mongoc_read_concern_t *read_concern) { if (read_concern) { if (read_concern->compiled.len) { bson_destroy (&read_concern->compiled); } bson_free (read_concern->level); bson_free (read_concern); } } const char * mongoc_read_concern_get_level (const mongoc_read_concern_t *read_concern) { BSON_ASSERT (read_concern); return read_concern->level; } /** * mongoc_read_concern_set_level: * @read_concern: A mongoc_read_concern_t. * @level: The read concern level * * Sets the read concern level. Any string is supported for future compatability * but MongoDB 3.2 only accepts "local" and "majority", aka: * - MONGOC_READ_CONCERN_LEVEL_LOCAL * - MONGOC_READ_CONCERN_LEVEL_MAJORITY * * If the @read_concern has already been frozen, calling this function will not * alter the read concern level. * * See the MongoDB docs for more information on readConcernLevel */ bool mongoc_read_concern_set_level (mongoc_read_concern_t *read_concern, const char *level) { BSON_ASSERT (read_concern); if (read_concern->frozen) { return false; } bson_free (read_concern->level); read_concern->level = bson_strdup (level); return true; } /** * mongoc_read_concern_get_bson: * @read_concern: A mongoc_read_concern_t. * * This is an internal function. * * Freeze the read concern if necessary and retrieve the encoded bson_t * representing the read concern. * * You may not modify the read concern further after calling this function. * * Returns: A bson_t that should not be modified or freed as it is owned by * the mongoc_read_concern_t instance. */ const bson_t * _mongoc_read_concern_get_bson (mongoc_read_concern_t *read_concern) { if (!read_concern->frozen) { _mongoc_read_concern_freeze (read_concern); } return &read_concern->compiled; } /** * mongoc_read_concern_freeze: * @read_concern: A mongoc_read_concern_t. * * This is an internal function. * * Freeze the read concern if necessary and encode it into a bson_ts which * represent the raw bson form and the get last error command form. * * You may not modify the read concern further after calling this function. */ static void _mongoc_read_concern_freeze (mongoc_read_concern_t *read_concern) { bson_t *compiled; BSON_ASSERT (read_concern); compiled = &read_concern->compiled; read_concern->frozen = true; bson_init (compiled); BSON_ASSERT (read_concern->level); BSON_APPEND_UTF8 (compiled, "level", read_concern->level); } libmongoc-1.3.1/src/mongoc/mongoc-read-concern.h000066400000000000000000000031161264720626300215400ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_READ_CONCERN_H #define MONGOC_READ_CONCERN_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS #define MONGOC_READ_CONCERN_LEVEL_LOCAL "local" #define MONGOC_READ_CONCERN_LEVEL_MAJORITY "majority" typedef struct _mongoc_read_concern_t mongoc_read_concern_t; mongoc_read_concern_t *mongoc_read_concern_new (void); mongoc_read_concern_t *mongoc_read_concern_copy (const mongoc_read_concern_t *read_concern); void mongoc_read_concern_destroy (mongoc_read_concern_t *read_concern); const char *mongoc_read_concern_get_level (const mongoc_read_concern_t *read_concern); bool mongoc_read_concern_set_level (mongoc_read_concern_t *read_concern, const char *level); BSON_END_DECLS #endif /* MONGOC_READ_CONCERN_H */ libmongoc-1.3.1/src/mongoc/mongoc-read-prefs-private.h000066400000000000000000000032701264720626300227010ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_READ_PREFS_PRIVATE_H #define MONGOC_READ_PREFS_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-cluster-private.h" #include "mongoc-read-prefs.h" BSON_BEGIN_DECLS struct _mongoc_read_prefs_t { mongoc_read_mode_t mode; bson_t tags; }; typedef struct _mongoc_apply_read_prefs_result_t { bson_t *query_with_read_prefs; bool query_owned; mongoc_query_flags_t flags; } mongoc_apply_read_prefs_result_t; #define READ_PREFS_RESULT_INIT { NULL, false, MONGOC_QUERY_NONE } void apply_read_preferences (const mongoc_read_prefs_t *read_prefs, const mongoc_server_stream_t *server_stream, const bson_t *query_bson, mongoc_query_flags_t initial_flags, mongoc_apply_read_prefs_result_t *result); void apply_read_prefs_result_cleanup (mongoc_apply_read_prefs_result_t *result); BSON_END_DECLS #endif /* MONGOC_READ_PREFS_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-read-prefs.c000066400000000000000000000210511264720626300212210ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-read-prefs-private.h" #include "mongoc-trace.h" mongoc_read_prefs_t * mongoc_read_prefs_new (mongoc_read_mode_t mode) { mongoc_read_prefs_t *read_prefs; read_prefs = (mongoc_read_prefs_t *)bson_malloc0(sizeof *read_prefs); read_prefs->mode = mode; bson_init(&read_prefs->tags); return read_prefs; } mongoc_read_mode_t mongoc_read_prefs_get_mode (const mongoc_read_prefs_t *read_prefs) { return read_prefs ? read_prefs->mode : MONGOC_READ_PRIMARY; } void mongoc_read_prefs_set_mode (mongoc_read_prefs_t *read_prefs, mongoc_read_mode_t mode) { BSON_ASSERT (read_prefs); BSON_ASSERT (mode <= MONGOC_READ_NEAREST); read_prefs->mode = mode; } const bson_t * mongoc_read_prefs_get_tags (const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (read_prefs); return &read_prefs->tags; } void mongoc_read_prefs_set_tags (mongoc_read_prefs_t *read_prefs, const bson_t *tags) { BSON_ASSERT (read_prefs); bson_destroy(&read_prefs->tags); if (tags) { bson_copy_to(tags, &read_prefs->tags); } else { bson_init(&read_prefs->tags); } } void mongoc_read_prefs_add_tag (mongoc_read_prefs_t *read_prefs, const bson_t *tag) { bson_t empty = BSON_INITIALIZER; char str[16]; int key; BSON_ASSERT (read_prefs); key = bson_count_keys (&read_prefs->tags); bson_snprintf (str, sizeof str, "%d", key); if (tag) { bson_append_document (&read_prefs->tags, str, -1, tag); } else { bson_append_document (&read_prefs->tags, str, -1, &empty); } } bool mongoc_read_prefs_is_valid (const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (read_prefs); /* * Tags are not supported with PRIMARY mode. */ if (read_prefs->mode == MONGOC_READ_PRIMARY) { if (!bson_empty(&read_prefs->tags)) { return false; } } return true; } void mongoc_read_prefs_destroy (mongoc_read_prefs_t *read_prefs) { if (read_prefs) { bson_destroy(&read_prefs->tags); bson_free(read_prefs); } } mongoc_read_prefs_t * mongoc_read_prefs_copy (const mongoc_read_prefs_t *read_prefs) { mongoc_read_prefs_t *ret = NULL; if (read_prefs) { ret = mongoc_read_prefs_new(read_prefs->mode); bson_copy_to(&read_prefs->tags, &ret->tags); } return ret; } static const char * _get_read_mode_string (mongoc_read_mode_t mode) { switch (mode) { case MONGOC_READ_PRIMARY: return "primary"; case MONGOC_READ_PRIMARY_PREFERRED: return "primaryPreferred"; case MONGOC_READ_SECONDARY: return "secondary"; case MONGOC_READ_SECONDARY_PREFERRED: return "secondaryPreferred"; case MONGOC_READ_NEAREST: return "nearest"; default: return ""; } } /* Update result with the read prefs, following Server Selection Spec. * The driver must have discovered the server is a mongos. */ static void _apply_read_preferences_mongos (const mongoc_read_prefs_t *read_prefs, const bson_t *query_bson, mongoc_apply_read_prefs_result_t *result /* OUT */) { mongoc_read_mode_t mode; const bson_t *tags = NULL; bson_t child; const char *mode_str; mode = mongoc_read_prefs_get_mode (read_prefs); if (read_prefs) { tags = mongoc_read_prefs_get_tags (read_prefs); } /* Server Selection Spec says: * * For mode 'primary', drivers MUST NOT set the slaveOK wire protocol flag * and MUST NOT use $readPreference * * For mode 'secondary', drivers MUST set the slaveOK wire protocol flag and * MUST also use $readPreference * * For mode 'primaryPreferred', drivers MUST set the slaveOK wire protocol * flag and MUST also use $readPreference * * For mode 'secondaryPreferred', drivers MUST set the slaveOK wire protocol * flag. If the read preference contains a non-empty tag_sets parameter, * drivers MUST use $readPreference; otherwise, drivers MUST NOT use * $readPreference * * For mode 'nearest', drivers MUST set the slaveOK wire protocol flag and * MUST also use $readPreference */ if (mode == MONGOC_READ_SECONDARY_PREFERRED && bson_empty0 (tags)) { result->flags |= MONGOC_QUERY_SLAVE_OK; } else if (mode != MONGOC_READ_PRIMARY) { result->flags |= MONGOC_QUERY_SLAVE_OK; /* Server Selection Spec: "When any $ modifier is used, including the * $readPreference modifier, the query MUST be provided using the $query * modifier". * * This applies to commands, too. */ result->query_with_read_prefs = bson_new (); result->query_owned = true; if (bson_has_field (query_bson, "$query")) { bson_concat (result->query_with_read_prefs, query_bson); } else { bson_append_document (result->query_with_read_prefs, "$query", 6, query_bson); } bson_append_document_begin (result->query_with_read_prefs, "$readPreference", 15, &child); mode_str = _get_read_mode_string (mode); bson_append_utf8 (&child, "mode", 4, mode_str, -1); if (!bson_empty0 (tags)) { bson_append_array (&child, "tags", 4, tags); } bson_append_document_end (result->query_with_read_prefs, &child); } } /* *-------------------------------------------------------------------------- * * apply_read_preferences -- * * Update @result based on @read prefs, following the Server Selection * Spec. * * Side effects: * Sets @result->query_with_read_prefs and @result->flags. * *-------------------------------------------------------------------------- */ void apply_read_preferences (const mongoc_read_prefs_t *read_prefs, const mongoc_server_stream_t *server_stream, const bson_t *query_bson, mongoc_query_flags_t initial_flags, mongoc_apply_read_prefs_result_t *result /* OUT */) { mongoc_server_description_type_t server_type; ENTRY; BSON_ASSERT (server_stream); BSON_ASSERT (query_bson); BSON_ASSERT (result); /* default values */ result->query_with_read_prefs = (bson_t *) query_bson; result->query_owned = false; result->flags = initial_flags; server_type = server_stream->sd->type; switch (server_stream->topology_type) { case MONGOC_TOPOLOGY_SINGLE: if (server_type == MONGOC_SERVER_MONGOS) { _apply_read_preferences_mongos (read_prefs, query_bson, result); } else { /* Server Selection Spec: for topology type single and server types * besides mongos, "clients MUST always set the slaveOK wire protocol * flag on reads to ensure that any server type can handle the * request." */ result->flags |= MONGOC_QUERY_SLAVE_OK; } break; case MONGOC_TOPOLOGY_RS_NO_PRIMARY: case MONGOC_TOPOLOGY_RS_WITH_PRIMARY: /* Server Selection Spec: for RS topology types, "For all read * preferences modes except primary, clients MUST set the slaveOK wire * protocol flag to ensure that any suitable server can handle the * request. Clients MUST NOT set the slaveOK wire protocol flag if the * read preference mode is primary. */ if (read_prefs && read_prefs->mode != MONGOC_READ_PRIMARY) { result->flags |= MONGOC_QUERY_SLAVE_OK; } break; case MONGOC_TOPOLOGY_SHARDED: _apply_read_preferences_mongos (read_prefs, query_bson, result); break; case MONGOC_TOPOLOGY_UNKNOWN: case MONGOC_TOPOLOGY_DESCRIPTION_TYPES: default: /* must not call _apply_read_preferences with unknown topology type */ BSON_ASSERT (false); } EXIT; } void apply_read_prefs_result_cleanup (mongoc_apply_read_prefs_result_t *result) { ENTRY; BSON_ASSERT (result); if (result->query_owned) { bson_destroy (result->query_with_read_prefs); } EXIT; } libmongoc-1.3.1/src/mongoc/mongoc-read-prefs.h000066400000000000000000000044121264720626300212300ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_READ_PREFS_H #define MONGOC_READ_PREFS_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef struct _mongoc_read_prefs_t mongoc_read_prefs_t; typedef enum { MONGOC_READ_PRIMARY = (1 << 0), MONGOC_READ_SECONDARY = (1 << 1), MONGOC_READ_PRIMARY_PREFERRED = (1 << 2) | MONGOC_READ_PRIMARY, MONGOC_READ_SECONDARY_PREFERRED = (1 << 2) | MONGOC_READ_SECONDARY, MONGOC_READ_NEAREST = (1 << 3) | MONGOC_READ_SECONDARY, } mongoc_read_mode_t; mongoc_read_prefs_t *mongoc_read_prefs_new (mongoc_read_mode_t read_mode); mongoc_read_prefs_t *mongoc_read_prefs_copy (const mongoc_read_prefs_t *read_prefs); void mongoc_read_prefs_destroy (mongoc_read_prefs_t *read_prefs); mongoc_read_mode_t mongoc_read_prefs_get_mode (const mongoc_read_prefs_t *read_prefs); void mongoc_read_prefs_set_mode (mongoc_read_prefs_t *read_prefs, mongoc_read_mode_t mode); const bson_t *mongoc_read_prefs_get_tags (const mongoc_read_prefs_t *read_prefs); void mongoc_read_prefs_set_tags (mongoc_read_prefs_t *read_prefs, const bson_t *tags); void mongoc_read_prefs_add_tag (mongoc_read_prefs_t *read_prefs, const bson_t *tag); bool mongoc_read_prefs_is_valid (const mongoc_read_prefs_t *read_prefs); BSON_END_DECLS #endif /* MONGOC_READ_PREFS_H */ libmongoc-1.3.1/src/mongoc/mongoc-rpc-private.h000066400000000000000000000103061264720626300214330ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_RPC_PRIVATE_H #define MONGOC_RPC_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include #include "mongoc-array-private.h" #include "mongoc-iovec.h" #include "mongoc-write-concern.h" #include "mongoc-flags.h" BSON_BEGIN_DECLS #define RPC(_name, _code) typedef struct { _code } mongoc_rpc_##_name##_t; #define ENUM_FIELD(_name) uint32_t _name; #define INT32_FIELD(_name) int32_t _name; #define INT64_FIELD(_name) int64_t _name; #define INT64_ARRAY_FIELD(_len, _name) int32_t _len; int64_t *_name; #define CSTRING_FIELD(_name) const char *_name; #define BSON_FIELD(_name) const uint8_t *_name; #define BSON_ARRAY_FIELD(_name) const uint8_t *_name; int32_t _name##_len; #define IOVEC_ARRAY_FIELD(_name) const mongoc_iovec_t *_name; int32_t n_##_name; mongoc_iovec_t _name##_recv; #define RAW_BUFFER_FIELD(_name) const uint8_t *_name; int32_t _name##_len; #define BSON_OPTIONAL(_check, _code) _code #include "op-delete.def" #include "op-get-more.def" #include "op-header.def" #include "op-insert.def" #include "op-kill-cursors.def" #include "op-msg.def" #include "op-query.def" #include "op-reply.def" #include "op-update.def" typedef union { mongoc_rpc_delete_t delete_; mongoc_rpc_get_more_t get_more; mongoc_rpc_header_t header; mongoc_rpc_insert_t insert; mongoc_rpc_kill_cursors_t kill_cursors; mongoc_rpc_msg_t msg; mongoc_rpc_query_t query; mongoc_rpc_reply_t reply; mongoc_rpc_update_t update; } mongoc_rpc_t; BSON_STATIC_ASSERT (sizeof (mongoc_rpc_header_t) == 16); BSON_STATIC_ASSERT (offsetof (mongoc_rpc_header_t, opcode) == offsetof (mongoc_rpc_reply_t, opcode)); #undef RPC #undef ENUM_FIELD #undef INT32_FIELD #undef INT64_FIELD #undef INT64_ARRAY_FIELD #undef CSTRING_FIELD #undef BSON_FIELD #undef BSON_ARRAY_FIELD #undef IOVEC_ARRAY_FIELD #undef BSON_OPTIONAL #undef RAW_BUFFER_FIELD void _mongoc_rpc_gather (mongoc_rpc_t *rpc, mongoc_array_t *array); bool _mongoc_rpc_needs_gle (mongoc_rpc_t *rpc, const mongoc_write_concern_t *write_concern); void _mongoc_rpc_swab_to_le (mongoc_rpc_t *rpc); void _mongoc_rpc_swab_from_le (mongoc_rpc_t *rpc); void _mongoc_rpc_printf (mongoc_rpc_t *rpc); bool _mongoc_rpc_scatter (mongoc_rpc_t *rpc, const uint8_t *buf, size_t buflen); bool _mongoc_rpc_reply_get_first (mongoc_rpc_reply_t *reply, bson_t *bson); void _mongoc_rpc_prep_command (mongoc_rpc_t *rpc, const char *cmd_ns, const bson_t *command, mongoc_query_flags_t flags); bool _mongoc_rpc_parse_command_error(mongoc_rpc_t *rpc, bson_error_t *error); bool _mongoc_rpc_parse_query_error (mongoc_rpc_t *rpc, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_RPC_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-rpc.c000066400000000000000000000565421264720626300177720ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc.h" #include "mongoc-rpc-private.h" #include "mongoc-trace.h" #define RPC(_name, _code) \ static void \ _mongoc_rpc_gather_##_name (mongoc_rpc_##_name##_t *rpc, \ mongoc_array_t *array) \ { \ mongoc_iovec_t iov; \ assert (rpc); \ assert (array); \ rpc->msg_len = 0; \ _code \ } #define INT32_FIELD(_name) \ iov.iov_base = (void *)&rpc->_name; \ iov.iov_len = 4; \ assert (iov.iov_len); \ rpc->msg_len += (int32_t)iov.iov_len; \ _mongoc_array_append_val(array, iov); #define ENUM_FIELD INT32_FIELD #define INT64_FIELD(_name) \ iov.iov_base = (void *)&rpc->_name; \ iov.iov_len = 8; \ assert (iov.iov_len); \ rpc->msg_len += (int32_t)iov.iov_len; \ _mongoc_array_append_val(array, iov); #define CSTRING_FIELD(_name) \ assert (rpc->_name); \ iov.iov_base = (void *)rpc->_name; \ iov.iov_len = strlen(rpc->_name) + 1; \ assert (iov.iov_len); \ rpc->msg_len += (int32_t)iov.iov_len; \ _mongoc_array_append_val(array, iov); #define BSON_FIELD(_name) \ do { \ int32_t __l; \ memcpy(&__l, rpc->_name, 4); \ __l = BSON_UINT32_FROM_LE(__l); \ iov.iov_base = (void *)rpc->_name; \ iov.iov_len = __l; \ assert (iov.iov_len); \ rpc->msg_len += (int32_t)iov.iov_len; \ _mongoc_array_append_val(array, iov); \ } while (0); #define BSON_OPTIONAL(_check, _code) \ if (rpc->_check) { _code } #define BSON_ARRAY_FIELD(_name) \ if (rpc->_name##_len) { \ iov.iov_base = (void *)rpc->_name; \ iov.iov_len = rpc->_name##_len; \ assert (iov.iov_len); \ rpc->msg_len += (int32_t)iov.iov_len; \ _mongoc_array_append_val(array, iov); \ } #define IOVEC_ARRAY_FIELD(_name) \ do { \ ssize_t _i; \ assert (rpc->n_##_name); \ for (_i = 0; _i < rpc->n_##_name; _i++) { \ assert (rpc->_name[_i].iov_len); \ rpc->msg_len += (int32_t)rpc->_name[_i].iov_len; \ _mongoc_array_append_val(array, rpc->_name[_i]); \ } \ } while (0); #define RAW_BUFFER_FIELD(_name) \ iov.iov_base = (void *)rpc->_name; \ iov.iov_len = rpc->_name##_len; \ assert (iov.iov_len); \ rpc->msg_len += (int32_t)iov.iov_len; \ _mongoc_array_append_val(array, iov); #define INT64_ARRAY_FIELD(_len, _name) \ iov.iov_base = (void *)&rpc->_len; \ iov.iov_len = 4; \ assert (iov.iov_len); \ rpc->msg_len += (int32_t)iov.iov_len; \ _mongoc_array_append_val(array, iov); \ iov.iov_base = (void *)rpc->_name; \ iov.iov_len = rpc->_len * 8; \ assert (iov.iov_len); \ rpc->msg_len += (int32_t)iov.iov_len; \ _mongoc_array_append_val(array, iov); #include "op-delete.def" #include "op-get-more.def" #include "op-insert.def" #include "op-kill-cursors.def" #include "op-msg.def" #include "op-query.def" #include "op-reply.def" #include "op-update.def" #undef RPC #undef ENUM_FIELD #undef INT32_FIELD #undef INT64_FIELD #undef INT64_ARRAY_FIELD #undef CSTRING_FIELD #undef BSON_FIELD #undef BSON_ARRAY_FIELD #undef IOVEC_ARRAY_FIELD #undef RAW_BUFFER_FIELD #undef BSON_OPTIONAL #if BSON_BYTE_ORDER == BSON_BIG_ENDIAN #define RPC(_name, _code) \ static void \ _mongoc_rpc_swab_to_le_##_name (mongoc_rpc_##_name##_t *rpc) \ { \ assert (rpc); \ _code \ } #define INT32_FIELD(_name) \ rpc->_name = BSON_UINT32_FROM_LE(rpc->_name); #define ENUM_FIELD INT32_FIELD #define INT64_FIELD(_name) \ rpc->_name = BSON_UINT64_FROM_LE(rpc->_name); #define CSTRING_FIELD(_name) #define BSON_FIELD(_name) #define BSON_ARRAY_FIELD(_name) #define IOVEC_ARRAY_FIELD(_name) #define BSON_OPTIONAL(_check, _code) \ if (rpc->_check) { _code } #define RAW_BUFFER_FIELD(_name) #define INT64_ARRAY_FIELD(_len, _name) \ do { \ ssize_t i; \ for (i = 0; i < rpc->_len; i++) { \ rpc->_name[i] = BSON_UINT64_FROM_LE(rpc->_name[i]); \ } \ rpc->_len = BSON_UINT32_FROM_LE(rpc->_len); \ } while (0); #include "op-delete.def" #include "op-get-more.def" #include "op-insert.def" #include "op-kill-cursors.def" #include "op-msg.def" #include "op-query.def" #include "op-reply.def" #include "op-update.def" #undef RPC #undef INT64_ARRAY_FIELD #define RPC(_name, _code) \ static void \ _mongoc_rpc_swab_from_le_##_name (mongoc_rpc_##_name##_t *rpc) \ { \ assert (rpc); \ _code \ } #define INT64_ARRAY_FIELD(_len, _name) \ do { \ ssize_t i; \ rpc->_len = BSON_UINT32_FROM_LE(rpc->_len); \ for (i = 0; i < rpc->_len; i++) { \ rpc->_name[i] = BSON_UINT64_FROM_LE(rpc->_name[i]); \ } \ } while (0); #include "op-delete.def" #include "op-get-more.def" #include "op-insert.def" #include "op-kill-cursors.def" #include "op-msg.def" #include "op-query.def" #include "op-reply.def" #include "op-update.def" #undef RPC #undef ENUM_FIELD #undef INT32_FIELD #undef INT64_FIELD #undef INT64_ARRAY_FIELD #undef CSTRING_FIELD #undef BSON_FIELD #undef BSON_ARRAY_FIELD #undef IOVEC_ARRAY_FIELD #undef BSON_OPTIONAL #undef RAW_BUFFER_FIELD #endif /* BSON_BYTE_ORDER == BSON_BIG_ENDIAN */ #define RPC(_name, _code) \ static void \ _mongoc_rpc_printf_##_name (mongoc_rpc_##_name##_t *rpc) \ { \ assert (rpc); \ _code \ } #define INT32_FIELD(_name) \ printf(" "#_name" : %d\n", rpc->_name); #define ENUM_FIELD(_name) \ printf(" "#_name" : %u\n", rpc->_name); #define INT64_FIELD(_name) \ printf(" "#_name" : %" PRIi64 "\n", (int64_t)rpc->_name); #define CSTRING_FIELD(_name) \ printf(" "#_name" : %s\n", rpc->_name); #define BSON_FIELD(_name) \ do { \ bson_t b; \ char *s; \ int32_t __l; \ memcpy(&__l, rpc->_name, 4); \ __l = BSON_UINT32_FROM_LE(__l); \ bson_init_static(&b, rpc->_name, __l); \ s = bson_as_json(&b, NULL); \ printf(" "#_name" : %s\n", s); \ bson_free(s); \ bson_destroy(&b); \ } while (0); #define BSON_ARRAY_FIELD(_name) \ do { \ bson_reader_t *__r; \ bool __eof; \ const bson_t *__b; \ __r = bson_reader_new_from_data(rpc->_name, rpc->_name##_len); \ while ((__b = bson_reader_read(__r, &__eof))) { \ char *s = bson_as_json(__b, NULL); \ printf(" "#_name" : %s\n", s); \ bson_free(s); \ } \ bson_reader_destroy(__r); \ } while (0); #define IOVEC_ARRAY_FIELD(_name) \ do { \ ssize_t _i; \ size_t _j; \ for (_i = 0; _i < rpc->n_##_name; _i++) { \ printf(" "#_name" : "); \ for (_j = 0; _j < rpc->_name[_i].iov_len; _j++) { \ uint8_t u; \ u = ((char *)rpc->_name[_i].iov_base)[_j]; \ printf(" %02x", u); \ } \ printf("\n"); \ } \ } while (0); #define BSON_OPTIONAL(_check, _code) \ if (rpc->_check) { _code } #define RAW_BUFFER_FIELD(_name) \ { \ ssize_t __i; \ printf(" "#_name" :"); \ for (__i = 0; __i < rpc->_name##_len; __i++) { \ uint8_t u; \ u = ((char *)rpc->_name)[__i]; \ printf(" %02x", u); \ } \ printf("\n"); \ } #define INT64_ARRAY_FIELD(_len, _name) \ do { \ ssize_t i; \ for (i = 0; i < rpc->_len; i++) { \ printf(" "#_name" : %" PRIi64 "\n", (int64_t)rpc->_name[i]); \ } \ rpc->_len = BSON_UINT32_FROM_LE(rpc->_len); \ } while (0); #include "op-delete.def" #include "op-get-more.def" #include "op-insert.def" #include "op-kill-cursors.def" #include "op-msg.def" #include "op-query.def" #include "op-reply.def" #include "op-update.def" #undef RPC #undef ENUM_FIELD #undef INT32_FIELD #undef INT64_FIELD #undef INT64_ARRAY_FIELD #undef CSTRING_FIELD #undef BSON_FIELD #undef BSON_ARRAY_FIELD #undef IOVEC_ARRAY_FIELD #undef BSON_OPTIONAL #undef RAW_BUFFER_FIELD #define RPC(_name, _code) \ static bool \ _mongoc_rpc_scatter_##_name (mongoc_rpc_##_name##_t *rpc, \ const uint8_t *buf, \ size_t buflen) \ { \ assert (rpc); \ assert (buf); \ assert (buflen); \ _code \ return true; \ } #define INT32_FIELD(_name) \ if (buflen < 4) { \ return false; \ } \ memcpy(&rpc->_name, buf, 4); \ buflen -= 4; \ buf += 4; #define ENUM_FIELD INT32_FIELD #define INT64_FIELD(_name) \ if (buflen < 8) { \ return false; \ } \ memcpy(&rpc->_name, buf, 8); \ buflen -= 8; \ buf += 8; #define INT64_ARRAY_FIELD(_len, _name) \ do { \ size_t needed; \ if (buflen < 4) { \ return false; \ } \ memcpy(&rpc->_len, buf, 4); \ buflen -= 4; \ buf += 4; \ needed = BSON_UINT32_FROM_LE(rpc->_len) * 8; \ if (needed > buflen) { \ return false; \ } \ rpc->_name = (int64_t*)buf; \ buf += needed; \ buflen -= needed; \ } while (0); #define CSTRING_FIELD(_name) \ do { \ size_t __i; \ bool found = false; \ for (__i = 0; __i < buflen; __i++) { \ if (!buf[__i]) { \ rpc->_name = (const char *)buf; \ buflen -= __i + 1; \ buf += __i + 1; \ found = true; \ break; \ } \ } \ if (!found) { \ return false; \ } \ } while (0); #define BSON_FIELD(_name) \ do { \ uint32_t __l; \ if (buflen < 4) { \ return false; \ } \ memcpy(&__l, buf, 4); \ __l = BSON_UINT32_FROM_LE(__l); \ if (__l < 5 || __l > buflen) { \ return false; \ } \ rpc->_name = (uint8_t *)buf; \ buf += __l; \ buflen -= __l; \ } while (0); #define BSON_ARRAY_FIELD(_name) \ rpc->_name = (uint8_t *)buf; \ rpc->_name##_len = (int32_t)buflen; \ buf = NULL; \ buflen = 0; #define BSON_OPTIONAL(_check, _code) \ if (buflen) { \ _code \ } #define IOVEC_ARRAY_FIELD(_name) \ rpc->_name##_recv.iov_base = (void *)buf; \ rpc->_name##_recv.iov_len = buflen; \ rpc->_name = &rpc->_name##_recv; \ rpc->n_##_name = 1; \ buf = NULL; \ buflen = 0; #define RAW_BUFFER_FIELD(_name) \ rpc->_name = (void *)buf; \ rpc->_name##_len = (int32_t)buflen; \ buf = NULL; \ buflen = 0; #include "op-delete.def" #include "op-get-more.def" #include "op-header.def" #include "op-insert.def" #include "op-kill-cursors.def" #include "op-msg.def" #include "op-query.def" #include "op-reply.def" #include "op-update.def" #undef RPC #undef ENUM_FIELD #undef INT32_FIELD #undef INT64_FIELD #undef INT64_ARRAY_FIELD #undef CSTRING_FIELD #undef BSON_FIELD #undef BSON_ARRAY_FIELD #undef IOVEC_ARRAY_FIELD #undef BSON_OPTIONAL #undef RAW_BUFFER_FIELD void _mongoc_rpc_gather (mongoc_rpc_t *rpc, mongoc_array_t *array) { switch ((mongoc_opcode_t)rpc->header.opcode) { case MONGOC_OPCODE_REPLY: _mongoc_rpc_gather_reply(&rpc->reply, array); return; case MONGOC_OPCODE_MSG: _mongoc_rpc_gather_msg(&rpc->msg, array); return; case MONGOC_OPCODE_UPDATE: _mongoc_rpc_gather_update(&rpc->update, array); return; case MONGOC_OPCODE_INSERT: _mongoc_rpc_gather_insert(&rpc->insert, array); return; case MONGOC_OPCODE_QUERY: _mongoc_rpc_gather_query(&rpc->query, array); return; case MONGOC_OPCODE_GET_MORE: _mongoc_rpc_gather_get_more(&rpc->get_more, array); return; case MONGOC_OPCODE_DELETE: _mongoc_rpc_gather_delete(&rpc->delete_, array); return; case MONGOC_OPCODE_KILL_CURSORS: _mongoc_rpc_gather_kill_cursors(&rpc->kill_cursors, array); return; default: MONGOC_WARNING("Unknown rpc type: 0x%08x", rpc->header.opcode); break; } } void _mongoc_rpc_swab_to_le (mongoc_rpc_t *rpc) { #if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN mongoc_opcode_t opcode; opcode = rpc->header.opcode; switch (opcode) { case MONGOC_OPCODE_REPLY: _mongoc_rpc_swab_to_le_reply(&rpc->reply); break; case MONGOC_OPCODE_MSG: _mongoc_rpc_swab_to_le_msg(&rpc->msg); break; case MONGOC_OPCODE_UPDATE: _mongoc_rpc_swab_to_le_update(&rpc->update); break; case MONGOC_OPCODE_INSERT: _mongoc_rpc_swab_to_le_insert(&rpc->insert); break; case MONGOC_OPCODE_QUERY: _mongoc_rpc_swab_to_le_query(&rpc->query); break; case MONGOC_OPCODE_GET_MORE: _mongoc_rpc_swab_to_le_get_more(&rpc->get_more); break; case MONGOC_OPCODE_DELETE: _mongoc_rpc_swab_to_le_delete(&rpc->delete_); break; case MONGOC_OPCODE_KILL_CURSORS: _mongoc_rpc_swab_to_le_kill_cursors(&rpc->kill_cursors); break; default: MONGOC_WARNING("Unknown rpc type: 0x%08x", opcode); break; } #endif } void _mongoc_rpc_swab_from_le (mongoc_rpc_t *rpc) { #if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN mongoc_opcode_t opcode; opcode = BSON_UINT32_FROM_LE(rpc->header.opcode); switch (opcode) { case MONGOC_OPCODE_REPLY: _mongoc_rpc_swab_from_le_reply(&rpc->reply); break; case MONGOC_OPCODE_MSG: _mongoc_rpc_swab_from_le_msg(&rpc->msg); break; case MONGOC_OPCODE_UPDATE: _mongoc_rpc_swab_from_le_update(&rpc->update); break; case MONGOC_OPCODE_INSERT: _mongoc_rpc_swab_from_le_insert(&rpc->insert); break; case MONGOC_OPCODE_QUERY: _mongoc_rpc_swab_from_le_query(&rpc->query); break; case MONGOC_OPCODE_GET_MORE: _mongoc_rpc_swab_from_le_get_more(&rpc->get_more); break; case MONGOC_OPCODE_DELETE: _mongoc_rpc_swab_from_le_delete(&rpc->delete_); break; case MONGOC_OPCODE_KILL_CURSORS: _mongoc_rpc_swab_from_le_kill_cursors(&rpc->kill_cursors); break; default: MONGOC_WARNING("Unknown rpc type: 0x%08x", rpc->header.opcode); break; } #endif } void _mongoc_rpc_printf (mongoc_rpc_t *rpc) { switch ((mongoc_opcode_t)rpc->header.opcode) { case MONGOC_OPCODE_REPLY: _mongoc_rpc_printf_reply(&rpc->reply); break; case MONGOC_OPCODE_MSG: _mongoc_rpc_printf_msg(&rpc->msg); break; case MONGOC_OPCODE_UPDATE: _mongoc_rpc_printf_update(&rpc->update); break; case MONGOC_OPCODE_INSERT: _mongoc_rpc_printf_insert(&rpc->insert); break; case MONGOC_OPCODE_QUERY: _mongoc_rpc_printf_query(&rpc->query); break; case MONGOC_OPCODE_GET_MORE: _mongoc_rpc_printf_get_more(&rpc->get_more); break; case MONGOC_OPCODE_DELETE: _mongoc_rpc_printf_delete(&rpc->delete_); break; case MONGOC_OPCODE_KILL_CURSORS: _mongoc_rpc_printf_kill_cursors(&rpc->kill_cursors); break; default: MONGOC_WARNING("Unknown rpc type: 0x%08x", rpc->header.opcode); break; } } bool _mongoc_rpc_scatter (mongoc_rpc_t *rpc, const uint8_t *buf, size_t buflen) { mongoc_opcode_t opcode; memset (rpc, 0, sizeof *rpc); if (BSON_UNLIKELY(buflen < 16)) { return false; } if (!_mongoc_rpc_scatter_header(&rpc->header, buf, 16)) { return false; } opcode = (mongoc_opcode_t)BSON_UINT32_FROM_LE(rpc->header.opcode); switch (opcode) { case MONGOC_OPCODE_REPLY: return _mongoc_rpc_scatter_reply(&rpc->reply, buf, buflen); case MONGOC_OPCODE_MSG: return _mongoc_rpc_scatter_msg(&rpc->msg, buf, buflen); case MONGOC_OPCODE_UPDATE: return _mongoc_rpc_scatter_update(&rpc->update, buf, buflen); case MONGOC_OPCODE_INSERT: return _mongoc_rpc_scatter_insert(&rpc->insert, buf, buflen); case MONGOC_OPCODE_QUERY: return _mongoc_rpc_scatter_query(&rpc->query, buf, buflen); case MONGOC_OPCODE_GET_MORE: return _mongoc_rpc_scatter_get_more(&rpc->get_more, buf, buflen); case MONGOC_OPCODE_DELETE: return _mongoc_rpc_scatter_delete(&rpc->delete_, buf, buflen); case MONGOC_OPCODE_KILL_CURSORS: return _mongoc_rpc_scatter_kill_cursors(&rpc->kill_cursors, buf, buflen); default: MONGOC_WARNING("Unknown rpc type: 0x%08x", opcode); return false; } } bool _mongoc_rpc_reply_get_first (mongoc_rpc_reply_t *reply, bson_t *bson) { int32_t len; if (!reply->documents || reply->documents_len < 4) { return false; } memcpy(&len, reply->documents, 4); len = BSON_UINT32_FROM_LE(len); if (reply->documents_len < len) { return false; } return bson_init_static(bson, reply->documents, len); } /* *-------------------------------------------------------------------------- * * _mongoc_rpc_needs_gle -- * * Checks to see if an rpc requires a getlasterror command to * determine the success of the rpc. * * The write_concern is checked to ensure that the caller wants * to know about a failure. * * Returns: * true if a getlasterror should be delivered; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool _mongoc_rpc_needs_gle (mongoc_rpc_t *rpc, const mongoc_write_concern_t *write_concern) { switch (rpc->header.opcode) { case MONGOC_OPCODE_REPLY: case MONGOC_OPCODE_QUERY: case MONGOC_OPCODE_MSG: case MONGOC_OPCODE_GET_MORE: case MONGOC_OPCODE_KILL_CURSORS: return false; case MONGOC_OPCODE_INSERT: case MONGOC_OPCODE_UPDATE: case MONGOC_OPCODE_DELETE: default: break; } if (!write_concern || !mongoc_write_concern_get_w(write_concern)) { return false; } return true; } /* *-------------------------------------------------------------------------- * * _mongoc_rpc_prep_command -- * * Prepare an RPC for mongoc_cluster_run_command_rpc. @cmd_ns and * @command must not be freed or modified while the RPC is in use. * * Side effects: * Fills out the RPC, including pointers into @cmd_ns and @command. * *-------------------------------------------------------------------------- */ void _mongoc_rpc_prep_command (mongoc_rpc_t *rpc, const char *cmd_ns, const bson_t *command, mongoc_query_flags_t flags) { rpc->query.msg_len = 0; rpc->query.request_id = 0; rpc->query.response_to = 0; rpc->query.opcode = MONGOC_OPCODE_QUERY; rpc->query.collection = cmd_ns; rpc->query.skip = 0; rpc->query.n_return = -1; rpc->query.fields = NULL; rpc->query.query = bson_get_data (command); /* Find, getMore And killCursors Commands Spec: "When sending a find command * rather than a legacy OP_QUERY find, only the slaveOk flag is honored." * For other cursor-typed commands like aggregate, only slaveOk can be set. * Clear bits except slaveOk; leave slaveOk set only if it is already. */ rpc->query.flags = flags & MONGOC_QUERY_SLAVE_OK; } static void _mongoc_populate_error (const bson_t *doc, bool is_command, bson_error_t *error) { uint32_t code = MONGOC_ERROR_QUERY_FAILURE; bson_iter_t iter; const char *msg = "Unknown query failure"; BSON_ASSERT (doc); if (!error) { return; } if (bson_iter_init_find (&iter, doc, "code") && BSON_ITER_HOLDS_INT32 (&iter)) { code = (uint32_t) bson_iter_int32 (&iter); } if (is_command && ((code == MONGOC_ERROR_PROTOCOL_ERROR) || (code == 13390))) { code = MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND; } if (bson_iter_init_find (&iter, doc, "$err") && BSON_ITER_HOLDS_UTF8 (&iter)) { msg = bson_iter_utf8 (&iter, NULL); } if (is_command && bson_iter_init_find (&iter, doc, "errmsg") && BSON_ITER_HOLDS_UTF8 (&iter)) { msg = bson_iter_utf8 (&iter, NULL); } bson_set_error(error, MONGOC_ERROR_QUERY, code, "%s", msg); } static bool _mongoc_rpc_parse_error (mongoc_rpc_t *rpc, bool is_command, bson_error_t *error /* OUT */) { bson_iter_t iter; bson_t b; ENTRY; BSON_ASSERT (rpc); if (rpc->header.opcode != MONGOC_OPCODE_REPLY) { bson_set_error(error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Received rpc other than OP_REPLY."); RETURN(true); } if ((rpc->reply.flags & MONGOC_REPLY_QUERY_FAILURE)) { if (_mongoc_rpc_reply_get_first(&rpc->reply, &b)) { _mongoc_populate_error (&b, is_command, error); bson_destroy(&b); } else { bson_set_error(error, MONGOC_ERROR_QUERY, MONGOC_ERROR_QUERY_FAILURE, "Unknown query failure."); } RETURN(true); } else if (is_command) { if (_mongoc_rpc_reply_get_first (&rpc->reply, &b)) { if (bson_iter_init_find (&iter, &b, "ok")) { if (bson_iter_as_bool (&iter)) { RETURN (false); } else { _mongoc_populate_error (&b, is_command, error); bson_destroy (&b); RETURN (true); } } } else { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Failed to decode document from the server."); RETURN (true); } } if ((rpc->reply.flags & MONGOC_REPLY_CURSOR_NOT_FOUND)) { bson_set_error(error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "The cursor is invalid or has expired."); RETURN(true); } RETURN(false); } /* *-------------------------------------------------------------------------- * * _mongoc_rpc_parse_command_error -- * * Check if a server OP_REPLY is a command error message. * Optionally fill out a bson_error_t from the server error. * * Returns: * true if the reply is an error message, false otherwise. * * Side effects: * If rpc is an error reply and @error is not NULL, set its * domain, code, and message. * *-------------------------------------------------------------------------- */ bool _mongoc_rpc_parse_command_error (mongoc_rpc_t *rpc, bson_error_t *error) { return _mongoc_rpc_parse_error (rpc, true, error); } /* *-------------------------------------------------------------------------- * * _mongoc_rpc_parse_query_error -- * * Check if a server OP_REPLY is a query error message. * Optionally fill out a bson_error_t from the server error. * * Returns: * true if the reply is an error message, false otherwise. * * Side effects: * If rpc is an error reply and @error is not NULL, set its * domain, code, and message. * *-------------------------------------------------------------------------- */ bool _mongoc_rpc_parse_query_error (mongoc_rpc_t *rpc, bson_error_t *error) { return _mongoc_rpc_parse_error (rpc, false, error); } libmongoc-1.3.1/src/mongoc/mongoc-sasl-private.h000066400000000000000000000047331264720626300216200ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_SASL_PRIVATE_H #define MONGOC_SASL_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_sasl_t mongoc_sasl_t; struct _mongoc_sasl_t { sasl_callback_t callbacks [4]; sasl_conn_t *conn; bool done; int step; char *mechanism; char *user; char *pass; char *service_name; char *service_host; sasl_interact_t *interact; }; void _mongoc_sasl_init (mongoc_sasl_t *sasl); void _mongoc_sasl_set_pass (mongoc_sasl_t *sasl, const char *pass); void _mongoc_sasl_set_user (mongoc_sasl_t *sasl, const char *user); void _mongoc_sasl_set_mechanism (mongoc_sasl_t *sasl, const char *mechanism); void _mongoc_sasl_set_service_name (mongoc_sasl_t *sasl, const char *service_name); void _mongoc_sasl_set_service_host (mongoc_sasl_t *sasl, const char *service_host); void _mongoc_sasl_destroy (mongoc_sasl_t *sasl); bool _mongoc_sasl_step (mongoc_sasl_t *sasl, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_SASL_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-sasl.c000066400000000000000000000204441264720626300201400ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-config.h" #ifdef MONGOC_ENABLE_SASL #include #include "mongoc-error.h" #include "mongoc-sasl-private.h" #include "mongoc-util-private.h" #ifndef SASL_CALLBACK_FN # define SASL_CALLBACK_FN(_f) ((int (*) (void))(_f)) #endif void _mongoc_sasl_set_mechanism (mongoc_sasl_t *sasl, const char *mechanism) { BSON_ASSERT (sasl); bson_free (sasl->mechanism); sasl->mechanism = mechanism ? bson_strdup (mechanism) : NULL; } static int _mongoc_sasl_get_pass (mongoc_sasl_t *sasl, int param_id, const char **result, unsigned *result_len) { BSON_ASSERT (sasl); BSON_ASSERT (param_id == SASL_CB_PASS); if (result) { *result = sasl->pass; } if (result_len) { *result_len = sasl->pass ? (unsigned) strlen (sasl->pass) : 0; } return (sasl->pass != NULL) ? SASL_OK : SASL_FAIL; } void _mongoc_sasl_set_pass (mongoc_sasl_t *sasl, const char *pass) { BSON_ASSERT (sasl); bson_free (sasl->pass); sasl->pass = pass ? bson_strdup (pass) : NULL; } static int _mongoc_sasl_get_user (mongoc_sasl_t *sasl, int param_id, const char **result, unsigned *result_len) { BSON_ASSERT (sasl); BSON_ASSERT ((param_id == SASL_CB_USER) || (param_id == SASL_CB_AUTHNAME)); if (result) { *result = sasl->user; } if (result_len) { *result_len = sasl->user ? (unsigned) strlen (sasl->user) : 0; } return (sasl->user != NULL) ? SASL_OK : SASL_FAIL; } void _mongoc_sasl_set_user (mongoc_sasl_t *sasl, const char *user) { BSON_ASSERT (sasl); bson_free (sasl->user); sasl->user = user ? bson_strdup (user) : NULL; } void _mongoc_sasl_set_service_host (mongoc_sasl_t *sasl, const char *service_host) { BSON_ASSERT (sasl); bson_free (sasl->service_host); sasl->service_host = service_host ? bson_strdup (service_host) : NULL; } void _mongoc_sasl_set_service_name (mongoc_sasl_t *sasl, const char *service_name) { BSON_ASSERT (sasl); bson_free (sasl->service_name); sasl->service_name = service_name ? bson_strdup (service_name) : NULL; } void _mongoc_sasl_init (mongoc_sasl_t *sasl) { sasl_callback_t callbacks [] = { { SASL_CB_AUTHNAME, SASL_CALLBACK_FN (_mongoc_sasl_get_user), sasl }, { SASL_CB_USER, SASL_CALLBACK_FN (_mongoc_sasl_get_user), sasl }, { SASL_CB_PASS, SASL_CALLBACK_FN (_mongoc_sasl_get_pass), sasl }, { SASL_CB_LIST_END } }; BSON_ASSERT (sasl); memset (sasl, 0, sizeof *sasl); memcpy (&sasl->callbacks, callbacks, sizeof callbacks); sasl->done = false; sasl->step = 0; sasl->conn = NULL; sasl->mechanism = NULL; sasl->user = NULL; sasl->pass = NULL; sasl->service_name = NULL; sasl->service_host = NULL; sasl->interact = NULL; } void _mongoc_sasl_destroy (mongoc_sasl_t *sasl) { BSON_ASSERT (sasl); if (sasl->conn) { sasl_dispose (&sasl->conn); } bson_free (sasl->user); bson_free (sasl->pass); bson_free (sasl->mechanism); bson_free (sasl->service_name); bson_free (sasl->service_host); } static bool _mongoc_sasl_is_failure (int status, bson_error_t *error) { bool ret = (status < 0); if (ret) { switch (status) { case SASL_NOMEM: bson_set_error (error, MONGOC_ERROR_SASL, status, "SASL Failrue: insufficient memory."); break; case SASL_NOMECH: bson_set_error (error, MONGOC_ERROR_SASL, status, "SASL Failure: failure to negotiate mechanism"); break; case SASL_BADPARAM: bson_set_error (error, MONGOC_ERROR_SASL, status, "Bad parameter supplied. Please file a bug " "with mongo-c-driver."); break; default: bson_set_error (error, MONGOC_ERROR_SASL, status, "SASL Failure: (%d): %s", status, sasl_errstring (status, NULL, NULL)); break; } } return ret; } static bool _mongoc_sasl_start (mongoc_sasl_t *sasl, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { const char *service_name = "mongodb"; const char *service_host = ""; const char *mechanism = NULL; const char *raw = NULL; unsigned raw_len = 0; int status; BSON_ASSERT (sasl); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); if (sasl->service_name) { service_name = sasl->service_name; } if (sasl->service_host) { service_host = sasl->service_host; } status = sasl_client_new (service_name, service_host, NULL, NULL, sasl->callbacks, 0, &sasl->conn); if (_mongoc_sasl_is_failure (status, error)) { return false; } status = sasl_client_start (sasl->conn, sasl->mechanism, &sasl->interact, &raw, &raw_len, &mechanism); if (_mongoc_sasl_is_failure (status, error)) { return false; } if ((0 != strcasecmp (mechanism, "GSSAPI")) && (0 != strcasecmp (mechanism, "PLAIN"))) { bson_set_error (error, MONGOC_ERROR_SASL, SASL_NOMECH, "SASL Failure: invalid mechanism \"%s\"", mechanism); return false; } status = sasl_encode64 (raw, raw_len, (char *)outbuf, outbufmax, outbuflen); if (_mongoc_sasl_is_failure (status, error)) { return false; } return true; } bool _mongoc_sasl_step (mongoc_sasl_t *sasl, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { const char *raw = NULL; unsigned rawlen = 0; int status; BSON_ASSERT (sasl); BSON_ASSERT (inbuf); BSON_ASSERT (outbuf); BSON_ASSERT (outbuflen); sasl->step++; if (sasl->step == 1) { return _mongoc_sasl_start (sasl, outbuf, outbufmax, outbuflen, error); } else if (sasl->step >= 10) { bson_set_error (error, MONGOC_ERROR_SASL, SASL_NOTDONE, "SASL Failure: maximum steps detected"); return false; } if (!inbuflen) { bson_set_error (error, MONGOC_ERROR_SASL, MONGOC_ERROR_CLIENT_AUTHENTICATE, "SASL Failure: no payload provided from server."); return false; } status = sasl_decode64 ((char *)inbuf, inbuflen, (char *)outbuf, outbufmax, outbuflen); if (_mongoc_sasl_is_failure (status, error)) { return false; } status = sasl_client_step (sasl->conn, (char *)outbuf, *outbuflen, &sasl->interact, &raw, &rawlen); if (_mongoc_sasl_is_failure (status, error)) { return false; } status = sasl_encode64 (raw, rawlen, (char *)outbuf, outbufmax, outbuflen); if (_mongoc_sasl_is_failure (status, error)) { return false; } return true; } #endif libmongoc-1.3.1/src/mongoc/mongoc-scram-private.h000066400000000000000000000036151264720626300217610ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #ifndef MONGOC_SCRAM_PRIVATE_H #define MONGOC_SCRAM_PRIVATE_H #include BSON_BEGIN_DECLS #define MONGOC_SCRAM_HASH_SIZE 20 typedef struct _mongoc_scram_t { bool done; int step; char *user; char *pass; uint8_t salted_password[MONGOC_SCRAM_HASH_SIZE]; char encoded_nonce[48]; int32_t encoded_nonce_len; uint8_t *auth_message; uint32_t auth_messagemax; uint32_t auth_messagelen; } mongoc_scram_t; void _mongoc_scram_startup(); void _mongoc_scram_init (mongoc_scram_t *scram); void _mongoc_scram_set_pass (mongoc_scram_t *scram, const char *pass); void _mongoc_scram_set_user (mongoc_scram_t *scram, const char *user); void _mongoc_scram_destroy (mongoc_scram_t *scram); bool _mongoc_scram_step (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_SCRAM_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-scram.c000066400000000000000000000544161264720626300203110ustar00rootroot00000000000000/* Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-config.h" #ifdef MONGOC_ENABLE_SSL #include #include "mongoc-error.h" #include "mongoc-scram-private.h" #include "mongoc-rand-private.h" #include "mongoc-util-private.h" #include "mongoc-b64-private.h" #include "mongoc-memcmp-private.h" #include #include #include #define MONGOC_SCRAM_SERVER_KEY "Server Key" #define MONGOC_SCRAM_CLIENT_KEY "Client Key" #define MONGOC_SCRAM_B64_ENCODED_SIZE(n) (2 * n) #define MONGOC_SCRAM_B64_HASH_SIZE \ MONGOC_SCRAM_B64_ENCODED_SIZE (MONGOC_SCRAM_HASH_SIZE) void _mongoc_scram_startup() { mongoc_b64_initialize_rmap(); } void _mongoc_scram_set_pass (mongoc_scram_t *scram, const char *pass) { BSON_ASSERT (scram); if (scram->pass) { bson_zero_free (scram->pass, strlen(scram->pass)); } scram->pass = pass ? bson_strdup (pass) : NULL; } void _mongoc_scram_set_user (mongoc_scram_t *scram, const char *user) { BSON_ASSERT (scram); bson_free (scram->user); scram->user = user ? bson_strdup (user) : NULL; } void _mongoc_scram_init (mongoc_scram_t *scram) { BSON_ASSERT (scram); memset (scram, 0, sizeof *scram); } void _mongoc_scram_destroy (mongoc_scram_t *scram) { BSON_ASSERT (scram); bson_free (scram->user); if (scram->pass) { bson_zero_free (scram->pass, strlen(scram->pass)); } bson_free (scram->auth_message); } static bool _mongoc_scram_buf_write (const char *src, int32_t src_len, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen) { if (src_len < 0) { src_len = (int32_t) strlen (src); } if (*outbuflen + src_len >= outbufmax) { return false; } memcpy (outbuf + *outbuflen, src, src_len); *outbuflen += src_len; return true; } /* generate client-first-message: * n,a=authzid,n=encoded-username,r=client-nonce * * note that a= is optional, so we aren't dealing with that here */ static bool _mongoc_scram_start (mongoc_scram_t *scram, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t nonce[24]; const char *ptr; bool rval = true; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); /* auth message is as big as the outbuf just because */ scram->auth_message = (uint8_t *)bson_malloc (outbufmax); scram->auth_messagemax = outbufmax; /* the server uses a 24 byte random nonce. so we do as well */ if (1 != _mongoc_rand_bytes (nonce, sizeof (nonce))) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not generate a cryptographically secure nonce in sasl step 1"); goto FAIL; } scram->encoded_nonce_len = mongoc_b64_ntop (nonce, sizeof (nonce), scram->encoded_nonce, sizeof (scram->encoded_nonce)); if (-1 == scram->encoded_nonce_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not encode nonce"); goto FAIL; } if (!_mongoc_scram_buf_write ("n,,n=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } for (ptr = scram->user; *ptr; ptr++) { /* RFC 5802 specifies that ',' and '=' and encoded as '=2C' and '=3D' * respectively in the user name */ switch (*ptr) { case ',': if (!_mongoc_scram_buf_write ("=2C", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } break; case '=': if (!_mongoc_scram_buf_write ("=3D", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } break; default: if (!_mongoc_scram_buf_write (ptr, 1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } break; } } if (!_mongoc_scram_buf_write (",r=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write (scram->encoded_nonce, scram->encoded_nonce_len, outbuf, outbufmax, outbuflen)) { goto BUFFER; } /* we have to keep track of the conversation to create a client proof later * on. This copies the message we're crafting from the 'n=' portion onwards * into a buffer we're managing */ if (!_mongoc_scram_buf_write ((char *)outbuf + 3, *outbuflen - 3, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",", -1, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } goto CLEANUP; BUFFER_AUTH: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer auth message in sasl step1"); goto FAIL; BUFFER: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer sasl step1"); goto FAIL; FAIL: rval = false; CLEANUP: return rval; } /* Compute the SCRAM step Hi() as defined in RFC5802 */ static void _mongoc_scram_salt_password (mongoc_scram_t *scram, const char *password, uint32_t password_len, const uint8_t *salt, uint32_t salt_len, uint32_t iterations) { uint8_t intermediate_digest[MONGOC_SCRAM_HASH_SIZE]; uint8_t start_key[MONGOC_SCRAM_HASH_SIZE]; /* Placeholder for HMAC return size, will always be scram::hashSize for HMAC SHA-1 */ uint32_t hash_len = 0; int i; int k; uint8_t *output = scram->salted_password; memcpy (start_key, salt, salt_len); start_key[salt_len] = 0; start_key[salt_len + 1] = 0; start_key[salt_len + 2] = 0; start_key[salt_len + 3] = 1; /* U1 = HMAC(input, salt + 0001) */ HMAC (EVP_sha1 (), password, password_len, start_key, sizeof (start_key), output, &hash_len); memcpy (intermediate_digest, output, MONGOC_SCRAM_HASH_SIZE); /* intermediateDigest contains Ui and output contains the accumulated XOR:ed result */ for (i = 2; i <= iterations; i++) { HMAC (EVP_sha1 (), password, password_len, intermediate_digest, sizeof (intermediate_digest), intermediate_digest, &hash_len); for (k = 0; k < MONGOC_SCRAM_HASH_SIZE; k++) { output[k] ^= intermediate_digest[k]; } } } static bool _mongoc_scram_sha1 (const unsigned char *input, const size_t input_len, unsigned char *output) { EVP_MD_CTX digest_ctx; bool rval = false; EVP_MD_CTX_init (&digest_ctx); if (1 != EVP_DigestInit_ex (&digest_ctx, EVP_sha1 (), NULL)) { goto cleanup; } if (1 != EVP_DigestUpdate (&digest_ctx, input, input_len)) { goto cleanup; } rval = (1 == EVP_DigestFinal_ex (&digest_ctx, output, NULL)); cleanup: EVP_MD_CTX_cleanup (&digest_ctx); return rval; } static bool _mongoc_scram_generate_client_proof (mongoc_scram_t *scram, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen) { /* ClientKey := HMAC(saltedPassword, "Client Key") */ uint8_t client_key[MONGOC_SCRAM_HASH_SIZE]; uint8_t stored_key[MONGOC_SCRAM_HASH_SIZE]; uint8_t client_signature[MONGOC_SCRAM_HASH_SIZE]; unsigned char client_proof[MONGOC_SCRAM_HASH_SIZE]; uint32_t hash_len = 0; int i; int r = 0; HMAC (EVP_sha1 (), scram->salted_password, MONGOC_SCRAM_HASH_SIZE, (uint8_t *)MONGOC_SCRAM_CLIENT_KEY, strlen (MONGOC_SCRAM_CLIENT_KEY), client_key, &hash_len); /* StoredKey := H(client_key) */ _mongoc_scram_sha1 (client_key, MONGOC_SCRAM_HASH_SIZE, stored_key); /* ClientSignature := HMAC(StoredKey, AuthMessage) */ HMAC (EVP_sha1 (), stored_key, MONGOC_SCRAM_HASH_SIZE, scram->auth_message, scram->auth_messagelen, client_signature, &hash_len); /* ClientProof := ClientKey XOR ClientSignature */ for (i = 0; i < MONGOC_SCRAM_HASH_SIZE; i++) { client_proof[i] = client_key[i] ^ client_signature[i]; } r = mongoc_b64_ntop (client_proof, sizeof (client_proof), (char *)outbuf + *outbuflen, outbufmax - *outbuflen); if (-1 == r) { return false; } *outbuflen += r; return true; } /* Parse server-first-message of the form: * r=client-nonce|server-nonce,s=user-salt,i=iteration-count * * Generate client-final-message of the form: * c=channel-binding(base64),r=client-nonce|server-nonce,p=client-proof */ static bool _mongoc_scram_step2 (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t *val_r = NULL; uint32_t val_r_len; uint8_t *val_s = NULL; uint32_t val_s_len; uint8_t *val_i = NULL; uint32_t val_i_len; uint8_t **current_val; uint32_t *current_val_len; const uint8_t *ptr; const uint8_t *next_comma; char *tmp; char *hashed_password; uint8_t decoded_salt[MONGOC_SCRAM_B64_HASH_SIZE]; int32_t decoded_salt_len; bool rval = true; int iterations; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); /* all our passwords go through md5 thanks to MONGODB-CR */ tmp = bson_strdup_printf ("%s:mongo:%s", scram->user, scram->pass); hashed_password = _mongoc_hex_md5 (tmp); bson_zero_free (tmp, strlen(tmp)); /* we need all of the incoming message for the final client proof */ if (!_mongoc_scram_buf_write ((char *)inbuf, inbuflen, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",", -1, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } for (ptr = inbuf; ptr < inbuf + inbuflen; ) { switch (*ptr) { case 'r': current_val = &val_r; current_val_len = &val_r_len; break; case 's': current_val = &val_s; current_val_len = &val_s_len; break; case 'i': current_val = &val_i; current_val_len = &val_i_len; break; default: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unknown key (%c) in sasl step 2", *ptr); goto FAIL; break; } ptr++; if (*ptr != '=') { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid parse state in sasl step 2"); goto FAIL; } ptr++; next_comma = (const uint8_t*)memchr (ptr, ',', (inbuf + inbuflen) - ptr); if (next_comma) { *current_val_len = (uint32_t) (next_comma - ptr); } else { *current_val_len = (uint32_t) ((inbuf + inbuflen) - ptr); } *current_val = (uint8_t *)bson_malloc (*current_val_len + 1); memcpy (*current_val, ptr, *current_val_len); (*current_val)[*current_val_len] = '\0'; if (next_comma) { ptr = next_comma + 1; } else { break; } } if (!val_r) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no r param in sasl step 2"); goto FAIL; } if (!val_s) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no s param in sasl step 2"); goto FAIL; } if (!val_i) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no i param in sasl step 2"); goto FAIL; } /* verify our nonce */ if (val_r_len < scram->encoded_nonce_len || mongoc_memcmp (val_r, scram->encoded_nonce, scram->encoded_nonce_len)) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: client nonce not repeated in sasl step 2"); } *outbuflen = 0; if (!_mongoc_scram_buf_write ("c=biws,r=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write ((char *)val_r, val_r_len, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write ((char *)outbuf, *outbuflen, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",p=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } decoded_salt_len = mongoc_b64_pton ((char *)val_s, decoded_salt, sizeof (decoded_salt)); if (-1 == decoded_salt_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unable to decode salt in sasl step2"); goto FAIL; } if (16 != decoded_salt_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid salt length of %d in sasl step2", decoded_salt_len); goto FAIL; } iterations = (int) bson_ascii_strtoll ((char *)val_i, &tmp, 10); /* tmp holds the location of the failed to parse character. So if it's * null, we got to the end of the string and didn't have a parse error */ if (*tmp) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unable to parse iterations in sasl step2"); goto FAIL; } _mongoc_scram_salt_password (scram, hashed_password, (uint32_t) strlen ( hashed_password), decoded_salt, decoded_salt_len, iterations); _mongoc_scram_generate_client_proof (scram, outbuf, outbufmax, outbuflen); goto CLEANUP; BUFFER_AUTH: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer auth message in sasl step2"); goto FAIL; BUFFER: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer sasl step2"); goto FAIL; FAIL: rval = false; CLEANUP: bson_free (val_r); bson_free (val_s); bson_free (val_i); if (hashed_password) { bson_zero_free (hashed_password, strlen(hashed_password)); } return rval; } static bool _mongoc_scram_verify_server_signature (mongoc_scram_t *scram, uint8_t *verification, uint32_t len) { /* ServerKey := HMAC(SaltedPassword, "Server Key") */ uint32_t hash_len; uint8_t server_key[MONGOC_SCRAM_HASH_SIZE]; char encoded_server_signature[MONGOC_SCRAM_B64_HASH_SIZE]; int32_t encoded_server_signature_len; uint8_t server_signature[MONGOC_SCRAM_HASH_SIZE]; HMAC (EVP_sha1 (), scram->salted_password, MONGOC_SCRAM_HASH_SIZE, (uint8_t *)MONGOC_SCRAM_SERVER_KEY, strlen (MONGOC_SCRAM_SERVER_KEY), server_key, &hash_len); /* ServerSignature := HMAC(ServerKey, AuthMessage) */ HMAC (EVP_sha1 (), server_key, MONGOC_SCRAM_HASH_SIZE, scram->auth_message, scram->auth_messagelen, server_signature, &hash_len); encoded_server_signature_len = mongoc_b64_ntop (server_signature, sizeof (server_signature), encoded_server_signature, sizeof (encoded_server_signature)); if (encoded_server_signature_len == -1) { return false; } return (len == encoded_server_signature_len) && (mongoc_memcmp (verification, encoded_server_signature, len) == 0); } static bool _mongoc_scram_step3 (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t *val_e = NULL; uint32_t val_e_len; uint8_t *val_v = NULL; uint32_t val_v_len; uint8_t **current_val; uint32_t *current_val_len; const uint8_t *ptr; const uint8_t *next_comma; bool rval = true; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); for (ptr = inbuf; ptr < inbuf + inbuflen; ) { switch (*ptr) { case 'e': current_val = &val_e; current_val_len = &val_e_len; break; case 'v': current_val = &val_v; current_val_len = &val_v_len; break; default: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unknown key (%c) in sasl step 3", *ptr); goto FAIL; break; } ptr++; if (*ptr != '=') { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid parse state in sasl step 3"); goto FAIL; } ptr++; next_comma = (const uint8_t*)memchr (ptr, ',', (inbuf + inbuflen) - ptr); if (next_comma) { *current_val_len = (uint32_t) (next_comma - ptr); } else { *current_val_len = (uint32_t) ((inbuf + inbuflen) - ptr); } *current_val = (uint8_t *)bson_malloc (*current_val_len + 1); memcpy (*current_val, ptr, *current_val_len); (*current_val)[*current_val_len] = '\0'; if (next_comma) { ptr = next_comma + 1; } else { break; } } *outbuflen = 0; if (val_e) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: authentication failure in sasl step 3 : %s", val_e); goto FAIL; } if (!val_v) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no v param in sasl step 3"); goto FAIL; } if (!_mongoc_scram_verify_server_signature (scram, val_v, val_v_len)) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not verify server signature in sasl step 3"); goto FAIL; } goto CLEANUP; FAIL: rval = false; CLEANUP: bson_free (val_e); bson_free (val_v); return rval; } bool _mongoc_scram_step (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { BSON_ASSERT (scram); BSON_ASSERT (inbuf); BSON_ASSERT (outbuf); BSON_ASSERT (outbuflen); scram->step++; switch (scram->step) { case 1: return _mongoc_scram_start (scram, outbuf, outbufmax, outbuflen, error); break; case 2: return _mongoc_scram_step2 (scram, inbuf, inbuflen, outbuf, outbufmax, outbuflen, error); break; case 3: return _mongoc_scram_step3 (scram, inbuf, inbuflen, outbuf, outbufmax, outbuflen, error); break; default: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_NOT_DONE, "SCRAM Failure: maximum steps detected"); return false; break; } return true; } #endif libmongoc-1.3.1/src/mongoc/mongoc-server-description-private.h000066400000000000000000000105411264720626300244770ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_SERVER_DESCRIPTION_PRIVATE_H #define MONGOC_SERVER_DESCRIPTION_PRIVATE_H #include "mongoc-server-description.h" #define MONGOC_DEFAULT_WIRE_VERSION 0 #define MONGOC_DEFAULT_WRITE_BATCH_SIZE 1000 #define MONGOC_DEFAULT_BSON_OBJ_SIZE 16 * 1024 * 1024 #define MONGOC_DEFAULT_MAX_MSG_SIZE 48000000 /* represent a server or topology with no replica set config version */ #define MONGOC_NO_SET_VERSION -1 typedef enum { MONGOC_SERVER_UNKNOWN, MONGOC_SERVER_STANDALONE, MONGOC_SERVER_MONGOS, MONGOC_SERVER_POSSIBLE_PRIMARY, MONGOC_SERVER_RS_PRIMARY, MONGOC_SERVER_RS_SECONDARY, MONGOC_SERVER_RS_ARBITER, MONGOC_SERVER_RS_OTHER, MONGOC_SERVER_RS_GHOST, MONGOC_SERVER_DESCRIPTION_TYPES, } mongoc_server_description_type_t; struct _mongoc_server_description_t { uint32_t id; mongoc_host_list_t host; int64_t round_trip_time; bson_t last_is_master; bool has_is_master; const char *connection_address; const char *me; /* The following fields are filled from the last_is_master and are zeroed on * parse. So order matters here. DON'T move set_name */ const char *set_name; bson_error_t error; mongoc_server_description_type_t type; int32_t min_wire_version; int32_t max_wire_version; int32_t max_msg_size; int32_t max_bson_obj_size; int32_t max_write_batch_size; bson_t hosts; bson_t passives; bson_t arbiters; bson_t tags; const char *current_primary; int64_t set_version; bson_oid_t election_id; }; void mongoc_server_description_init (mongoc_server_description_t *sd, const char *address, uint32_t id); bool mongoc_server_description_has_rs_member (mongoc_server_description_t *description, const char *address); bool mongoc_server_description_has_set_version (mongoc_server_description_t *description); bool mongoc_server_description_has_election_id (mongoc_server_description_t *description); void mongoc_server_description_cleanup (mongoc_server_description_t *sd); void mongoc_server_description_reset (mongoc_server_description_t *sd); void mongoc_server_description_set_state (mongoc_server_description_t *description, mongoc_server_description_type_t type); void mongoc_server_description_set_set_version (mongoc_server_description_t *description, int64_t set_version); void mongoc_server_description_set_election_id (mongoc_server_description_t *description, const bson_oid_t *election_id); void mongoc_server_description_update_rtt (mongoc_server_description_t *server, int64_t new_time); void mongoc_server_description_handle_ismaster ( mongoc_server_description_t *sd, const bson_t *reply, int64_t rtt_msec, bson_error_t *error); size_t mongoc_server_description_filter_eligible ( mongoc_server_description_t **descriptions, size_t description_len, const mongoc_read_prefs_t *read_prefs); #endif libmongoc-1.3.1/src/mongoc/mongoc-server-description.c000066400000000000000000000471731264720626300230350ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-host-list.h" #include "mongoc-host-list-private.h" #include "mongoc-read-prefs.h" #include "mongoc-server-description-private.h" #include "mongoc-trace.h" #include "mongoc-uri.h" #include "mongoc-util-private.h" #include #define ALPHA 0.2 static uint8_t kMongocEmptyBson[] = { 5, 0, 0, 0, 0 }; static bson_oid_t kObjectIdZero = { {0} }; /* Destroy allocated resources within @description, but don't free it */ void mongoc_server_description_cleanup (mongoc_server_description_t *sd) { BSON_ASSERT(sd); bson_destroy (&sd->last_is_master); } /* Reset fields inside this sd, but keep same id, host information, and RTT, and leave ismaster in empty inited state */ void mongoc_server_description_reset (mongoc_server_description_t *sd) { BSON_ASSERT(sd); /* set other fields to default or empty states. election_id is zeroed. */ memset (&sd->set_name, 0, sizeof (*sd) - ((char*)&sd->set_name - (char*)sd)); sd->set_name = NULL; sd->type = MONGOC_SERVER_UNKNOWN; sd->min_wire_version = MONGOC_DEFAULT_WIRE_VERSION; sd->max_wire_version = MONGOC_DEFAULT_WIRE_VERSION; sd->max_msg_size = MONGOC_DEFAULT_MAX_MSG_SIZE; sd->max_bson_obj_size = MONGOC_DEFAULT_BSON_OBJ_SIZE; sd->max_write_batch_size = MONGOC_DEFAULT_WRITE_BATCH_SIZE; /* always leave last ismaster in an init-ed state until we destroy sd */ bson_destroy (&sd->last_is_master); bson_init (&sd->last_is_master); sd->has_is_master = false; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_init -- * * Initialize a new server_description_t. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_server_description_init (mongoc_server_description_t *sd, const char *address, uint32_t id) { ENTRY; BSON_ASSERT (sd); BSON_ASSERT (address); memset (sd, 0, sizeof *sd); sd->id = id; sd->type = MONGOC_SERVER_UNKNOWN; sd->round_trip_time = -1; sd->set_name = NULL; sd->set_version = MONGOC_NO_SET_VERSION; sd->current_primary = NULL; if (!_mongoc_host_list_from_string(&sd->host, address)) { MONGOC_WARNING("Failed to parse uri for %s", address); return; } sd->connection_address = sd->host.host_and_port; sd->me = NULL; sd->min_wire_version = MONGOC_DEFAULT_WIRE_VERSION; sd->max_wire_version = MONGOC_DEFAULT_WIRE_VERSION; sd->max_msg_size = MONGOC_DEFAULT_MAX_MSG_SIZE; sd->max_bson_obj_size = MONGOC_DEFAULT_BSON_OBJ_SIZE; sd->max_write_batch_size = MONGOC_DEFAULT_WRITE_BATCH_SIZE; bson_init_static (&sd->hosts, kMongocEmptyBson, sizeof (kMongocEmptyBson)); bson_init_static (&sd->passives, kMongocEmptyBson, sizeof (kMongocEmptyBson)); bson_init_static (&sd->arbiters, kMongocEmptyBson, sizeof (kMongocEmptyBson)); bson_init_static (&sd->tags, kMongocEmptyBson, sizeof (kMongocEmptyBson)); bson_init (&sd->last_is_master); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_destroy -- * * Destroy allocated resources within @description and free * @description. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_server_description_destroy (mongoc_server_description_t *description) { ENTRY; mongoc_server_description_cleanup(description); bson_free(description); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_has_rs_member -- * * Return true if this address is included in server's list of rs * members, false otherwise. * * Returns: * true, false * * Side effects: * None * *-------------------------------------------------------------------------- */ bool mongoc_server_description_has_rs_member(mongoc_server_description_t *server, const char *address) { bson_iter_t member_iter; const bson_t *rs_members[3]; int i; if (server->type != MONGOC_SERVER_UNKNOWN) { rs_members[0] = &server->hosts; rs_members[1] = &server->arbiters; rs_members[2] = &server->passives; for (i = 0; i < 3; i++) { bson_iter_init (&member_iter, rs_members[i]); while (bson_iter_next (&member_iter)) { if (strcasecmp (address, bson_iter_utf8 (&member_iter, NULL)) == 0) { return true; } } } } return false; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_has_set_version -- * * Did this server's ismaster response have a "setVersion" field? * * Returns: * True if the server description's setVersion is set. * *-------------------------------------------------------------------------- */ bool mongoc_server_description_has_set_version (mongoc_server_description_t *description) { return description->set_version != MONGOC_NO_SET_VERSION; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_has_election_id -- * * Did this server's ismaster response have an "electionId" field? * * Returns: * True if the server description's electionId is set. * *-------------------------------------------------------------------------- */ bool mongoc_server_description_has_election_id (mongoc_server_description_t *description) { return 0 != bson_oid_compare (&description->election_id, &kObjectIdZero); } /* *-------------------------------------------------------------------------- * * mongoc_server_description_id -- * * Get the id of this server. * * Returns: * Server's id. * *-------------------------------------------------------------------------- */ uint32_t mongoc_server_description_id (mongoc_server_description_t *description) { return description->id; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_host -- * * Return a reference to the host associated with this server description. * * Returns: * A mongoc_host_list_t *, this server description's host. * *-------------------------------------------------------------------------- */ mongoc_host_list_t * mongoc_server_description_host (mongoc_server_description_t *description) { return &description->host; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_set_state -- * * Set the server description's server type. * *-------------------------------------------------------------------------- */ void mongoc_server_description_set_state (mongoc_server_description_t *description, mongoc_server_description_type_t type) { description->type = type; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_set_set_version -- * * Set the replica set version of this server. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_server_description_set_set_version (mongoc_server_description_t *description, int64_t set_version) { description->set_version = set_version; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_set_election_id -- * * Set the election_id of this server. Copies the given ObjectId or, * if it is NULL, zeroes description's election_id. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_server_description_set_election_id (mongoc_server_description_t *description, const bson_oid_t *election_id) { if (election_id) { bson_oid_copy_unsafe (election_id, &description->election_id); } else { bson_oid_copy_unsafe (&kObjectIdZero, &description->election_id); } } /* *------------------------------------------------------------------------- * * mongoc_server_description_update_rtt -- * * Calculate this server's rtt calculation using an exponentially- * weighted moving average formula. * * Side effects: * None. * *------------------------------------------------------------------------- */ void mongoc_server_description_update_rtt (mongoc_server_description_t *server, int64_t new_time) { if (server->round_trip_time == -1) { server->round_trip_time = new_time; } else { server->round_trip_time = ALPHA * new_time + (1 - ALPHA) * server->round_trip_time; } } /* *------------------------------------------------------------------------- * * Called during SDAM, from topology description's ismaster handler. * *------------------------------------------------------------------------- */ void mongoc_server_description_handle_ismaster ( mongoc_server_description_t *sd, const bson_t *ismaster_response, int64_t rtt_msec, bson_error_t *error) { bson_iter_t iter; bool is_master = false; bool is_shard = false; bool is_secondary = false; bool is_arbiter = false; bool is_replicaset = false; bool is_hidden = false; const uint8_t *bytes; uint32_t len; int num_keys = 0; ENTRY; BSON_ASSERT (sd); mongoc_server_description_reset (sd); if (!ismaster_response) { EXIT; } bson_destroy (&sd->last_is_master); bson_copy_to (ismaster_response, &sd->last_is_master); sd->has_is_master = true; bson_iter_init (&iter, &sd->last_is_master); while (bson_iter_next (&iter)) { num_keys++; if (strcmp ("ok", bson_iter_key (&iter)) == 0) { /* ismaster responses never have ok: 0, but spec requires we check */ if (! bson_iter_as_bool (&iter)) goto failure; } else if (strcmp ("ismaster", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_BOOL (&iter)) goto failure; is_master = bson_iter_bool (&iter); } else if (strcmp ("me", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_UTF8 (&iter)) goto failure; sd->me = bson_iter_utf8 (&iter, NULL); } else if (strcmp ("maxMessageSizeBytes", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; sd->max_msg_size = bson_iter_int32 (&iter); } else if (strcmp ("maxBsonObjectSize", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; sd->max_bson_obj_size = bson_iter_int32 (&iter); } else if (strcmp ("maxWriteBatchSize", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; sd->max_write_batch_size = bson_iter_int32 (&iter); } else if (strcmp ("minWireVersion", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; sd->min_wire_version = bson_iter_int32 (&iter); } else if (strcmp ("maxWireVersion", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_INT32 (&iter)) goto failure; sd->max_wire_version = bson_iter_int32 (&iter); } else if (strcmp ("msg", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_UTF8 (&iter)) goto failure; is_shard = !!bson_iter_utf8 (&iter, NULL); } else if (strcmp ("setName", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_UTF8 (&iter)) goto failure; sd->set_name = bson_iter_utf8 (&iter, NULL); } else if (strcmp ("setVersion", bson_iter_key (&iter)) == 0) { mongoc_server_description_set_set_version (sd, bson_iter_as_int64 (&iter)); } else if (strcmp ("electionId", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_OID (&iter)) goto failure; mongoc_server_description_set_election_id (sd, bson_iter_oid (&iter)); } else if (strcmp ("secondary", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_BOOL (&iter)) goto failure; is_secondary = bson_iter_bool (&iter); } else if (strcmp ("hosts", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_ARRAY (&iter)) goto failure; bson_iter_array (&iter, &len, &bytes); bson_init_static (&sd->hosts, bytes, len); } else if (strcmp ("passives", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_ARRAY (&iter)) goto failure; bson_iter_array (&iter, &len, &bytes); bson_init_static (&sd->passives, bytes, len); } else if (strcmp ("arbiters", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_ARRAY (&iter)) goto failure; bson_iter_array (&iter, &len, &bytes); bson_init_static (&sd->arbiters, bytes, len); } else if (strcmp ("primary", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_UTF8 (&iter)) goto failure; sd->current_primary = bson_iter_utf8 (&iter, NULL); } else if (strcmp ("arbiterOnly", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_BOOL (&iter)) goto failure; is_arbiter = bson_iter_bool (&iter); } else if (strcmp ("isreplicaset", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_BOOL (&iter)) goto failure; is_replicaset = bson_iter_bool (&iter); } else if (strcmp ("tags", bson_iter_key (&iter)) == 0) { if (! BSON_ITER_HOLDS_DOCUMENT (&iter)) goto failure; bson_iter_document (&iter, &len, &bytes); bson_init_static (&sd->tags, bytes, len); } else if (strcmp ("hidden", bson_iter_key (&iter)) == 0) { is_hidden = bson_iter_bool (&iter); } } if (is_shard) { sd->type = MONGOC_SERVER_MONGOS; } else if (sd->set_name) { if (is_hidden) { sd->type = MONGOC_SERVER_RS_OTHER; } else if (is_master) { sd->type = MONGOC_SERVER_RS_PRIMARY; } else if (is_secondary) { sd->type = MONGOC_SERVER_RS_SECONDARY; } else if (is_arbiter) { sd->type = MONGOC_SERVER_RS_ARBITER; } else { sd->type = MONGOC_SERVER_RS_OTHER; } } else if (is_replicaset) { sd->type = MONGOC_SERVER_RS_GHOST; } else if (num_keys > 0) { sd->type = MONGOC_SERVER_STANDALONE; } else { sd->type = MONGOC_SERVER_UNKNOWN; } mongoc_server_description_update_rtt(sd, rtt_msec); EXIT; failure: sd->type = MONGOC_SERVER_UNKNOWN; sd->round_trip_time = -1; EXIT; } /* *------------------------------------------------------------------------- * * mongoc_server_description_new_copy -- * * A copy of a server description that you must destroy, or NULL. * *------------------------------------------------------------------------- */ mongoc_server_description_t * mongoc_server_description_new_copy (const mongoc_server_description_t *description) { mongoc_server_description_t *copy; if (!description) { return NULL; } copy = (mongoc_server_description_t *)bson_malloc0(sizeof (*copy)); copy->id = description->id; memcpy (©->host, &description->host, sizeof (copy->host)); copy->round_trip_time = -1; copy->connection_address = copy->host.host_and_port; /* wait for handle_ismaster to fill these in properly */ copy->has_is_master = false; copy->set_version = MONGOC_NO_SET_VERSION; bson_init_static (©->hosts, kMongocEmptyBson, sizeof (kMongocEmptyBson)); bson_init_static (©->passives, kMongocEmptyBson, sizeof (kMongocEmptyBson)); bson_init_static (©->arbiters, kMongocEmptyBson, sizeof (kMongocEmptyBson)); bson_init_static (©->tags, kMongocEmptyBson, sizeof (kMongocEmptyBson)); bson_init (©->last_is_master); if (description->has_is_master) { mongoc_server_description_handle_ismaster (copy, &description->last_is_master, description->round_trip_time, NULL); } /* Preserve the error */ memcpy (©->error, &description->error, sizeof copy->error); return copy; } /* *------------------------------------------------------------------------- * * mongoc_server_description_filter_eligible -- * * Given a set of server descriptions, determine which are eligible * as per the Server Selection spec. Determines the number of * eligible servers, and sets any servers that are NOT eligible to * NULL in the descriptions set. * * Returns: * Number of eligible servers found. * *------------------------------------------------------------------------- */ size_t mongoc_server_description_filter_eligible ( mongoc_server_description_t **descriptions, size_t description_len, const mongoc_read_prefs_t *read_prefs) { const bson_t *rp_tags; bson_iter_t rp_tagset_iter; bson_iter_t rp_iter; bson_iter_t sd_iter; uint32_t rp_len; uint32_t sd_len; const char *rp_val; const char *sd_val; bool *sd_matched = NULL; size_t found; size_t i; size_t rval = 0; if (!read_prefs) { /* NULL read_prefs is PRIMARY, no tags to filter by */ return description_len; } rp_tags = mongoc_read_prefs_get_tags (read_prefs); if (bson_count_keys (rp_tags) == 0) { return description_len; } sd_matched = (bool *) bson_malloc0 (sizeof(bool) * description_len); bson_iter_init (&rp_tagset_iter, rp_tags); /* for each read preference tagset */ while (bson_iter_next (&rp_tagset_iter)) { found = description_len; for (i = 0; i < description_len; i++) { sd_matched[i] = true; bson_iter_recurse (&rp_tagset_iter, &rp_iter); while (bson_iter_next (&rp_iter)) { /* TODO: can we have non-utf8 tags? */ rp_val = bson_iter_utf8 (&rp_iter, &rp_len); if (bson_iter_init_find (&sd_iter, &descriptions[i]->tags, bson_iter_key (&rp_iter))) { /* If the server description has that key */ sd_val = bson_iter_utf8 (&sd_iter, &sd_len); if (! (sd_len == rp_len && (0 == memcmp(rp_val, sd_val, rp_len)))) { /* If the key value doesn't match, no match */ sd_matched[i] = false; found--; } } else { /* If the server description doesn't have that key, no match */ sd_matched[i] = false; found--; break; } } } if (found) { for (i = 0; i < description_len; i++) { if (! sd_matched[i]) { descriptions[i] = NULL; } } rval = found; goto CLEANUP; } } for (i = 0; i < description_len; i++) { if (! sd_matched[i]) { descriptions[i] = NULL; } } CLEANUP: bson_free (sd_matched); return rval; } libmongoc-1.3.1/src/mongoc/mongoc-server-description.h000066400000000000000000000023351264720626300230310ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_SERVER_DESCRIPTION_H #define MONGOC_SERVER_DESCRIPTION_H #include #include "mongoc-array-private.h" #include "mongoc-read-prefs.h" #include "mongoc-host-list.h" typedef struct _mongoc_server_description_t mongoc_server_description_t; void mongoc_server_description_destroy (mongoc_server_description_t *description); mongoc_server_description_t * mongoc_server_description_new_copy (const mongoc_server_description_t *description); uint32_t mongoc_server_description_id (mongoc_server_description_t *description); mongoc_host_list_t * mongoc_server_description_host (mongoc_server_description_t *description); #endif libmongoc-1.3.1/src/mongoc/mongoc-server-stream-private.h000066400000000000000000000034611264720626300234520ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_SERVER_STREAM_H #define MONGOC_SERVER_STREAM_H #include "mongoc-config.h" #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-topology-description-private.h" #include "mongoc-server-description-private.h" #include "mongoc-stream.h" BSON_BEGIN_DECLS typedef struct _mongoc_server_stream_t { mongoc_topology_description_type_t topology_type; mongoc_server_description_t *sd; /* owned */ mongoc_stream_t *stream; /* borrowed */ } mongoc_server_stream_t; mongoc_server_stream_t * mongoc_server_stream_new (mongoc_topology_description_type_t topology_type, mongoc_server_description_t *sd, mongoc_stream_t *stream); int32_t mongoc_server_stream_max_bson_obj_size (mongoc_server_stream_t *server_stream); int32_t mongoc_server_stream_max_msg_size (mongoc_server_stream_t *server_stream); int32_t mongoc_server_stream_max_write_batch_size (mongoc_server_stream_t *server_stream); void mongoc_server_stream_cleanup (mongoc_server_stream_t *server_stream); BSON_END_DECLS #endif /* MONGOC_SERVER_STREAM_H */ libmongoc-1.3.1/src/mongoc/mongoc-server-stream.c000066400000000000000000000057241264720626300220010ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-cluster-private.h" #include "mongoc-server-stream-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "server-stream" #define COALESCE(x, y) ((x == 0) ? (y) : (x)) mongoc_server_stream_t * mongoc_server_stream_new (mongoc_topology_description_type_t topology_type, mongoc_server_description_t *sd, mongoc_stream_t *stream) { mongoc_server_stream_t *server_stream; BSON_ASSERT (sd); BSON_ASSERT (stream); server_stream = bson_malloc (sizeof (mongoc_server_stream_t)); server_stream->topology_type = topology_type; server_stream->sd = sd; /* becomes owned */ server_stream->stream = stream; /* merely borrowed */ return server_stream; } void mongoc_server_stream_cleanup (mongoc_server_stream_t *server_stream) { if (server_stream) { mongoc_server_description_destroy (server_stream->sd); bson_free (server_stream); } } /* *-------------------------------------------------------------------------- * * mongoc_server_stream_max_bson_obj_size -- * * Return the max bson object size for the given server stream. * *-------------------------------------------------------------------------- */ int32_t mongoc_server_stream_max_bson_obj_size (mongoc_server_stream_t *server_stream) { return COALESCE (server_stream->sd->max_bson_obj_size, MONGOC_DEFAULT_BSON_OBJ_SIZE); } /* *-------------------------------------------------------------------------- * * mongoc_server_stream_max_msg_size -- * * Return the max message size for the given server stream. * *-------------------------------------------------------------------------- */ int32_t mongoc_server_stream_max_msg_size (mongoc_server_stream_t *server_stream) { return COALESCE (server_stream->sd->max_msg_size, MONGOC_DEFAULT_MAX_MSG_SIZE); } /* *-------------------------------------------------------------------------- * * mongoc_server_stream_max_write_batch_size -- * * Return the max write batch size for the given server stream. * *-------------------------------------------------------------------------- */ int32_t mongoc_server_stream_max_write_batch_size (mongoc_server_stream_t *server_stream) { return COALESCE (server_stream->sd->max_write_batch_size, MONGOC_DEFAULT_WRITE_BATCH_SIZE); }libmongoc-1.3.1/src/mongoc/mongoc-set-private.h000066400000000000000000000053301264720626300214430ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_SET_PRIVATE_H #define MONGOC_SET_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef void (*mongoc_set_item_dtor)(void *item, void *ctx); /* return true to continue iteration, false to stop */ typedef bool (*mongoc_set_for_each_cb_t)(void *item, void *ctx); typedef struct { uint32_t id; void *item; } mongoc_set_item_t; typedef struct { mongoc_set_item_t *items; size_t items_len; size_t items_allocated; mongoc_set_item_dtor dtor; void *dtor_ctx; } mongoc_set_t; mongoc_set_t * mongoc_set_new (size_t nitems, mongoc_set_item_dtor dtor, void *dtor_ctx); void mongoc_set_add (mongoc_set_t *set, uint32_t id, void *item); void mongoc_set_rm (mongoc_set_t *set, uint32_t id); void * mongoc_set_get (mongoc_set_t *set, uint32_t id); void * mongoc_set_get_item (mongoc_set_t *set, int idx); void mongoc_set_destroy (mongoc_set_t *set); /* loops over the set safe-ish. * * Caveats: * - you can add items at any iteration * - if you remove elements other than the one you're currently looking at, * you may see it later in the iteration */ void mongoc_set_for_each (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx); /* first item in set for which "cb" returns true */ void * mongoc_set_find_item (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx); /* id of first item in set for which "cb" returns true, or 0. */ uint32_t mongoc_set_find_id (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx); BSON_END_DECLS #endif /* MONGOC_SET_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-set.c000066400000000000000000000113641264720626300177720ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-set-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "set" mongoc_set_t * mongoc_set_new (size_t nitems, mongoc_set_item_dtor dtor, void *dtor_ctx) { mongoc_set_t *set = (mongoc_set_t *)bson_malloc (sizeof (*set)); set->items_allocated = nitems; set->items = (mongoc_set_item_t *)bson_malloc (sizeof (*set->items) * set->items_allocated); set->items_len = 0; set->dtor = dtor; set->dtor_ctx = dtor_ctx; return set; } static int mongoc_set_id_cmp (const void *a_, const void *b_) { mongoc_set_item_t *a = (mongoc_set_item_t *)a_; mongoc_set_item_t *b = (mongoc_set_item_t *)b_; if (a->id == b->id) { return 0; } return a->id < b->id ? -1 : 1; } void mongoc_set_add (mongoc_set_t *set, uint32_t id, void *item) { if (set->items_len >= set->items_allocated) { set->items_allocated *= 2; set->items = (mongoc_set_item_t *)bson_realloc (set->items, sizeof (*set->items) * set->items_allocated); } set->items[set->items_len].id = id; set->items[set->items_len].item = item; set->items_len++; if (set->items_len > 1 && set->items[set->items_len - 2].id > id) { qsort (set->items, set->items_len, sizeof (*set->items), mongoc_set_id_cmp); } } void mongoc_set_rm (mongoc_set_t *set, uint32_t id) { mongoc_set_item_t *ptr; mongoc_set_item_t key; int i; key.id = id; ptr = (mongoc_set_item_t *)bsearch (&key, set->items, set->items_len, sizeof (key), mongoc_set_id_cmp); if (ptr) { set->dtor(ptr->item, set->dtor_ctx); i = ptr - set->items; if (i != set->items_len - 1) { memmove (set->items + i, set->items + i + 1, (set->items_len - (i + 1)) * sizeof (key)); } set->items_len--; } } void * mongoc_set_get (mongoc_set_t *set, uint32_t id) { mongoc_set_item_t *ptr; mongoc_set_item_t key; key.id = id; ptr = (mongoc_set_item_t *)bsearch (&key, set->items, set->items_len, sizeof (key), mongoc_set_id_cmp); return ptr ? ptr->item : NULL; } void * mongoc_set_get_item (mongoc_set_t *set, int idx) { BSON_ASSERT (set); BSON_ASSERT (idx < set->items_len); return set->items[idx].item; } void mongoc_set_destroy (mongoc_set_t *set) { int i; for (i = 0; i < set->items_len; i++) { set->dtor(set->items[i].item, set->dtor_ctx); } bson_free (set->items); bson_free (set); } void mongoc_set_for_each (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx) { size_t i; mongoc_set_item_t *old_set; size_t items_len; items_len = set->items_len; old_set = (mongoc_set_item_t *)bson_malloc (sizeof (*old_set) * items_len); memcpy (old_set, set->items, sizeof (*old_set) * items_len); for (i = 0; i < items_len; i++) { if (!cb (old_set[i].item, ctx)) { break; } } bson_free (old_set); } static mongoc_set_item_t * _mongoc_set_find (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx) { size_t i; size_t items_len; mongoc_set_item_t *item; items_len = set->items_len; for (i = 0; i < items_len; i++) { item = &set->items[i]; if (cb (item->item, ctx)) { return item; } } return NULL; } void * mongoc_set_find_item (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx) { mongoc_set_item_t *item; if ((item = _mongoc_set_find (set, cb, ctx))) { return item->item; } return NULL; } uint32_t mongoc_set_find_id (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx) { mongoc_set_item_t *item; if ((item = _mongoc_set_find (set, cb, ctx))) { return item->id; } return 0; } libmongoc-1.3.1/src/mongoc/mongoc-socket-private.h000066400000000000000000000022541264720626300221420ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_SOCKET_PRIVATE_H #define MONGOC_SOCKET_PRIVATE_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include "mongoc-socket.h" BSON_BEGIN_DECLS struct _mongoc_socket_t { #ifdef _WIN32 SOCKET sd; #else int sd; #endif int errno_; int domain; }; mongoc_socket_t *mongoc_socket_accept_ex (mongoc_socket_t *sock, int64_t expire_at, uint16_t *port); BSON_END_DECLS #endif /* MONGOC_SOCKET_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-socket.c000066400000000000000000000704221264720626300204670ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "mongoc-counters-private.h" #include "mongoc-errno-private.h" #include "mongoc-socket-private.h" #include "mongoc-host-list.h" #include "mongoc-socket-private.h" #include "mongoc-trace.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "socket" #define OPERATION_EXPIRED(expire_at) \ ((expire_at >= 0) && (expire_at < (bson_get_monotonic_time()))) /* *-------------------------------------------------------------------------- * * _mongoc_socket_setnonblock -- * * A helper to set a socket in nonblocking mode. * * Returns: * true if successful; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool #ifdef _WIN32 _mongoc_socket_setnonblock (SOCKET sd) #else _mongoc_socket_setnonblock (int sd) #endif { #ifdef _WIN32 u_long io_mode = 1; return (NO_ERROR == ioctlsocket (sd, FIONBIO, &io_mode)); #else int flags; flags = fcntl (sd, F_GETFL, sd); return (-1 != fcntl (sd, F_SETFL, (flags | O_NONBLOCK))); #endif } /* *-------------------------------------------------------------------------- * * _mongoc_socket_wait -- * * A single socket poll helper. * * @events: in most cases should be POLLIN or POLLOUT. * * @expire_at should be an absolute time at which to expire using * the monotonic clock (bson_get_monotonic_time(), which is in * microseconds). Or zero to not block at all. Or -1 to block * forever. * * Returns: * true if an event matched. otherwise false. * a timeout will return false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool #ifdef _WIN32 _mongoc_socket_wait (SOCKET sd, /* IN */ #else _mongoc_socket_wait (int sd, /* IN */ #endif int events, /* IN */ int64_t expire_at) /* IN */ { #ifdef _WIN32 WSAPOLLFD pfd; #else struct pollfd pfd; #endif int ret; int timeout; int64_t now; ENTRY; BSON_ASSERT (events); pfd.fd = sd; #ifdef _WIN32 pfd.events = events; #else pfd.events = events | POLLERR | POLLHUP; #endif pfd.revents = 0; now = bson_get_monotonic_time(); for (;;) { if (expire_at < 0) { timeout = -1; } else if (expire_at == 0) { timeout = 0; } else { timeout = (int)((expire_at - now) / 1000L); if (timeout < 0) { timeout = 0; } } #ifdef _WIN32 ret = WSAPoll (&pfd, 1, timeout); if (ret == SOCKET_ERROR) { errno = WSAGetLastError(); ret = -1; } #else ret = poll (&pfd, 1, timeout); #endif if (ret > 0) { /* Something happened, so return that */ #ifdef _WIN32 RETURN (0 != (pfd.revents & (events | POLLHUP | POLLERR))); #else RETURN (0 != (pfd.revents & events)); #endif } else if (ret < 0) { /* poll itself failed */ TRACE("errno is: %d", errno); if (MONGOC_ERRNO_IS_AGAIN(errno)) { now = bson_get_monotonic_time(); if (expire_at < now) { RETURN (false); } else { continue; } } else { /* poll failed for some non-transient reason */ RETURN (false); } } else { /* poll timed out */ RETURN (false); } } } /* *-------------------------------------------------------------------------- * * _mongoc_socket_poll -- * * A multi-socket poll helper. * * @events: in most cases should be POLLIN or POLLOUT. * * @expire_at should be an absolute time at which to expire using * the monotonic clock (bson_get_monotonic_time(), which is in * microseconds). Or zero to not block at all. Or -1 to block * forever. * * Returns: * true if an event matched. otherwise false. * a timeout will return false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ ssize_t mongoc_socket_poll (mongoc_socket_poll_t *sds, /* IN */ size_t nsds, /* IN */ int32_t timeout) /* IN */ { #ifdef _WIN32 WSAPOLLFD *pfds; #else struct pollfd *pfds; #endif int ret; int i; ENTRY; BSON_ASSERT (sds); #ifdef _WIN32 pfds = (WSAPOLLFD *)bson_malloc(sizeof(*pfds) * nsds); #else pfds = (struct pollfd *)bson_malloc(sizeof(*pfds) * nsds); #endif for (i = 0; i < nsds; i++) { pfds[i].fd = sds[i].socket->sd; #ifdef _WIN32 pfds[i].events = sds[i].events; #else pfds[i].events = sds[i].events | POLLERR | POLLHUP; #endif pfds[i].revents = 0; } #ifdef _WIN32 ret = WSAPoll (pfds, nsds, timeout); if (ret == SOCKET_ERROR) { MONGOC_WARNING ("WSAGetLastError(): %d", WSAGetLastError ()); ret = -1; } #else ret = poll (pfds, nsds, timeout); #endif for (i = 0; i < nsds; i++) { sds[i].revents = pfds[i].revents; } bson_free(pfds); return ret; } static bool #ifdef _WIN32 _mongoc_socket_setnodelay (SOCKET sd) /* IN */ #else _mongoc_socket_setnodelay (int sd) /* IN */ #endif { #ifdef _WIN32 BOOL optval = 1; #else int optval = 1; #endif int ret; ENTRY; errno = 0; ret = setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof optval); #ifdef _WIN32 if (ret == SOCKET_ERROR) { MONGOC_WARNING ("WSAGetLastError(): %d", (int)WSAGetLastError ()); } #endif RETURN (ret == 0); } /* *-------------------------------------------------------------------------- * * mongoc_socket_errno -- * * Returns the last error on the socket. * * Returns: * An integer errno, or 0 on no error. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_errno (mongoc_socket_t *sock) /* IN */ { BSON_ASSERT (sock); TRACE("Current errno: %d", sock->errno_); return sock->errno_; } /* *-------------------------------------------------------------------------- * * _mongoc_socket_capture_errno -- * * Save the errno state for contextual use. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _mongoc_socket_capture_errno (mongoc_socket_t *sock) /* IN */ { #ifdef _WIN32 errno = sock->errno_ = WSAGetLastError (); #else sock->errno_ = errno; #endif TRACE("setting errno: %d", sock->errno_); } /* *-------------------------------------------------------------------------- * * _mongoc_socket_errno_is_again -- * * Check to see if we should attempt to make further progress * based on the error of the last operation. * * Returns: * true if we should try again. otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_socket_errno_is_again (mongoc_socket_t *sock) /* IN */ { TRACE("errno is: %d", sock->errno_); return MONGOC_ERRNO_IS_AGAIN (sock->errno_); } /* *-------------------------------------------------------------------------- * * mongoc_socket_accept -- * * Wrapper for BSD socket accept(). Handles portability between * BSD sockets and WinSock2 on Windows Vista and newer. * * Returns: * NULL upon failure to accept or timeout. * A newly allocated mongoc_socket_t on success. * * Side effects: * *port contains the client port number. * *-------------------------------------------------------------------------- */ mongoc_socket_t * mongoc_socket_accept (mongoc_socket_t *sock, /* IN */ int64_t expire_at) /* IN */ { return mongoc_socket_accept_ex (sock, expire_at, NULL); } /* *-------------------------------------------------------------------------- * * mongoc_socket_accept_ex -- * * Private synonym for mongoc_socket_accept, returning client port. * * Returns: * NULL upon failure to accept or timeout. * A newly allocated mongoc_socket_t on success. * * Side effects: * *port contains the client port number. * *-------------------------------------------------------------------------- */ mongoc_socket_t * mongoc_socket_accept_ex (mongoc_socket_t *sock, /* IN */ int64_t expire_at, /* IN */ uint16_t *port) /* OUT */ { mongoc_socket_t *client; struct sockaddr_in addr; socklen_t addrlen = sizeof addr; bool try_again = false; bool failed = false; #ifdef _WIN32 SOCKET sd; #else int sd; #endif ENTRY; BSON_ASSERT (sock); again: errno = 0; sd = accept (sock->sd, (struct sockaddr *) &addr, &addrlen); _mongoc_socket_capture_errno (sock); #ifdef _WIN32 failed = (sd == INVALID_SOCKET); #else failed = (sd == -1); #endif try_again = (failed && _mongoc_socket_errno_is_again (sock)); if (failed && try_again) { if (_mongoc_socket_wait (sock->sd, POLLIN, expire_at)) { GOTO (again); } RETURN (NULL); } else if (failed) { RETURN (NULL); } else if (!_mongoc_socket_setnonblock (sd)) { #ifdef _WIN32 closesocket (sd); #else close (sd); #endif RETURN (NULL); } client = (mongoc_socket_t *)bson_malloc0 (sizeof *client); client->sd = sd; if (port) { *port = ntohs (addr.sin_port); } if (!_mongoc_socket_setnodelay (client->sd)) { MONGOC_WARNING ("Failed to enable TCP_NODELAY."); } RETURN (client); } /* *-------------------------------------------------------------------------- * * mongo_socket_bind -- * * A wrapper around bind(). * * Returns: * 0 on success, -1 on failure and errno is set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_bind (mongoc_socket_t *sock, /* IN */ const struct sockaddr *addr, /* IN */ socklen_t addrlen) /* IN */ { int ret; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (addr); BSON_ASSERT (addrlen); ret = bind (sock->sd, addr, addrlen); _mongoc_socket_capture_errno (sock); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_socket_close -- * * Closes the underlying socket. * * In general, you probably don't want to handle the result from * this. That could cause race conditions in the case of preemtion * during system call (EINTR). * * Returns: * 0 on success, -1 on failure. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_close (mongoc_socket_t *sock) /* IN */ { ENTRY; BSON_ASSERT (sock); #ifdef _WIN32 if (sock->sd != INVALID_SOCKET) { shutdown (sock->sd, SD_BOTH); if (0 == closesocket (sock->sd)) { sock->sd = INVALID_SOCKET; } else { _mongoc_socket_capture_errno (sock); RETURN(-1); } } RETURN(0); #else if (sock->sd != -1) { shutdown (sock->sd, SHUT_RDWR); if (0 == close (sock->sd)) { sock->sd = -1; } else { _mongoc_socket_capture_errno (sock); RETURN(-1); } } RETURN(0); #endif } /* *-------------------------------------------------------------------------- * * mongoc_socket_connect -- * * Performs a socket connection but will fail if @expire_at is * reached by the monotonic clock. * * Returns: * 0 if success, otherwise -1 and errno is set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_connect (mongoc_socket_t *sock, /* IN */ const struct sockaddr *addr, /* IN */ socklen_t addrlen, /* IN */ int64_t expire_at) /* IN */ { bool try_again = false; bool failed = false; int ret; int optval; socklen_t optlen = sizeof optval; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (addr); BSON_ASSERT (addrlen); ret = connect (sock->sd, addr, addrlen); #ifdef _WIN32 if (ret == SOCKET_ERROR) { #else if (ret == -1) { #endif _mongoc_socket_capture_errno (sock); failed = true; try_again = _mongoc_socket_errno_is_again (sock); } if (failed && try_again) { if (_mongoc_socket_wait (sock->sd, POLLOUT, expire_at)) { optval = -1; ret = getsockopt (sock->sd, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen); if ((ret == 0) && (optval == 0)) { RETURN (0); } else { errno = sock->errno_ = optval; } } RETURN (-1); } else if (failed) { RETURN (-1); } else { RETURN (0); } } /* *-------------------------------------------------------------------------- * * mongoc_socket_destroy -- * * Cleanup after a mongoc_socket_t structure, possibly closing * underlying sockets. * * Returns: * None. * * Side effects: * @sock is freed and should be considered invalid. * *-------------------------------------------------------------------------- */ void mongoc_socket_destroy (mongoc_socket_t *sock) /* IN */ { if (sock) { mongoc_socket_close (sock); bson_free (sock); } } /* *-------------------------------------------------------------------------- * * mongoc_socket_listen -- * * Listen for incoming requests with a backlog up to @backlog. * * If @backlog is zero, a sensible default will be chosen. * * Returns: * true if successful; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_listen (mongoc_socket_t *sock, /* IN */ unsigned int backlog) /* IN */ { int ret; ENTRY; BSON_ASSERT (sock); if (backlog == 0) { backlog = 10; } ret = listen (sock->sd, backlog); _mongoc_socket_capture_errno (sock); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_socket_new -- * * Create a new socket. * * Free the result mongoc_socket_destroy(). * * Returns: * A newly allocated socket. * NULL on failure. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_socket_t * mongoc_socket_new (int domain, /* IN */ int type, /* IN */ int protocol) /* IN */ { mongoc_socket_t *sock; #ifdef _WIN32 SOCKET sd; #else int sd; #endif ENTRY; sd = socket (domain, type, protocol); #ifdef _WIN32 if (sd == INVALID_SOCKET) { #else if (sd == -1) { #endif RETURN (NULL); } if (!_mongoc_socket_setnonblock (sd)) { GOTO (fail); } if (domain != AF_UNIX && !_mongoc_socket_setnodelay (sd)) { MONGOC_WARNING ("Failed to enable TCP_NODELAY."); } sock = (mongoc_socket_t *)bson_malloc0 (sizeof *sock); sock->sd = sd; sock->domain = domain; RETURN (sock); fail: #ifdef _WIN32 closesocket (sd); #else close (sd); #endif RETURN (NULL); } /* *-------------------------------------------------------------------------- * * mongoc_socket_recv -- * * A portable wrapper around recv() that also respects an absolute * timeout. * * @expire_at is 0 for no blocking, -1 for infinite blocking, * or a time using the monotonic clock to expire. Calculate this * using bson_get_monotonic_time() + N_MICROSECONDS. * * Returns: * The number of bytes received on success. * 0 on end of stream. * -1 on failure. * * Side effects: * @buf will be read into. * *-------------------------------------------------------------------------- */ ssize_t mongoc_socket_recv (mongoc_socket_t *sock, /* IN */ void *buf, /* OUT */ size_t buflen, /* IN */ int flags, /* IN */ int64_t expire_at) /* IN */ { ssize_t ret = 0; bool failed = false; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (buf); BSON_ASSERT (buflen); again: sock->errno_ = 0; #ifdef _WIN32 ret = recv (sock->sd, (char *)buf, (int)buflen, flags); failed = (ret == SOCKET_ERROR); #else ret = recv (sock->sd, buf, buflen, flags); failed = (ret == -1); #endif if (failed) { _mongoc_socket_capture_errno (sock); if (_mongoc_socket_errno_is_again (sock) && _mongoc_socket_wait (sock->sd, POLLIN, expire_at)) { GOTO (again); } } if (failed) { RETURN (-1); } mongoc_counter_streams_ingress_add (ret); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_socket_setsockopt -- * * A wrapper around setsockopt(). * * Returns: * 0 on success, -1 on failure. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_setsockopt (mongoc_socket_t *sock, /* IN */ int level, /* IN */ int optname, /* IN */ const void *optval, /* IN */ socklen_t optlen) /* IN */ { int ret; ENTRY; BSON_ASSERT (sock); ret = setsockopt (sock->sd, level, optname, optval, optlen); _mongoc_socket_capture_errno (sock); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_socket_send -- * * A simplified wrapper around mongoc_socket_sendv(). * * @expire_at is 0 for no blocking, -1 for infinite blocking, * or a time using the monotonic clock to expire. Calculate this * using bson_get_monotonic_time() + N_MICROSECONDS. * * Returns: * -1 on failure. number of bytes written on success. * * Side effects: * None. * *-------------------------------------------------------------------------- */ ssize_t mongoc_socket_send (mongoc_socket_t *sock, /* IN */ const void *buf, /* IN */ size_t buflen, /* IN */ int64_t expire_at) /* IN */ { mongoc_iovec_t iov; BSON_ASSERT (sock); BSON_ASSERT (buf); BSON_ASSERT (buflen); iov.iov_base = (void *)buf; iov.iov_len = buflen; return mongoc_socket_sendv (sock, &iov, 1, expire_at); } /* *-------------------------------------------------------------------------- * * _mongoc_socket_try_sendv_slow -- * * A slow variant of _mongoc_socket_try_sendv() that sends each * iovec entry one by one. This can happen if we hit EMSGSIZE * with sendmsg() on various POSIX systems or WSASend()+WSAEMSGSIZE * on Windows. * * Returns: * the number of bytes sent or -1 and errno is set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static ssize_t _mongoc_socket_try_sendv_slow (mongoc_socket_t *sock, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt) /* IN */ { ssize_t ret = 0; size_t i; ssize_t wrote; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); for (i = 0; i < iovcnt; i++) { wrote = send (sock->sd, iov [i].iov_base, iov [i].iov_len, 0); #ifdef _WIN32 if (wrote == SOCKET_ERROR) { #else if (wrote == -1) { #endif _mongoc_socket_capture_errno (sock); if (!_mongoc_socket_errno_is_again (sock)) { RETURN (-1); } RETURN (ret ? ret : -1); } ret += wrote; if (wrote != iov [i].iov_len) { RETURN (ret); } } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_socket_try_sendv -- * * Helper used by mongoc_socket_sendv() to try to write as many * bytes to the underlying socket until the socket buffer is full. * * This is performed in a non-blocking fashion. * * Returns: * -1 on failure. the number of bytes written on success. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static ssize_t _mongoc_socket_try_sendv (mongoc_socket_t *sock, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt) /* IN */ { #ifdef _WIN32 DWORD dwNumberofBytesSent = 0; int ret; #else struct msghdr msg; ssize_t ret; #endif ENTRY; BSON_ASSERT (sock); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); DUMP_IOVEC (sendbuf, iov, iovcnt); #ifdef _WIN32 ret = WSASend (sock->sd, (LPWSABUF)iov, iovcnt, &dwNumberofBytesSent, 0, NULL, NULL); TRACE("WSASend sent: %ld (out of: %ld), ret: %d", dwNumberofBytesSent, iov->iov_len, ret); #else memset (&msg, 0, sizeof msg); msg.msg_iov = iov; msg.msg_iovlen = (int) iovcnt; ret = sendmsg (sock->sd, &msg, # ifdef MSG_NOSIGNAL MSG_NOSIGNAL); # else 0); # endif TRACE("Send %ld out of %ld bytes", ret, iov->iov_len); #endif #ifdef _WIN32 if (ret == SOCKET_ERROR) { #else if (ret == -1) { #endif _mongoc_socket_capture_errno (sock); /* * Check to see if we have sent an iovec too large for sendmsg to * complete. If so, we need to fallback to the slow path of multiple * send() commands. */ #ifdef _WIN32 if (mongoc_socket_errno (sock) == WSAEMSGSIZE) { #else if (mongoc_socket_errno (sock) == EMSGSIZE) { #endif RETURN(_mongoc_socket_try_sendv_slow (sock, iov, iovcnt)); } RETURN (-1); } #ifdef _WIN32 RETURN (dwNumberofBytesSent); #else RETURN (ret); #endif } /* *-------------------------------------------------------------------------- * * mongoc_socket_sendv -- * * A wrapper around using sendmsg() to send an iovec. * This also deals with the structure differences between * WSABUF and struct iovec. * * @expire_at is 0 for no blocking, -1 for infinite blocking, * or a time using the monotonic clock to expire. Calculate this * using bson_get_monotonic_time() + N_MICROSECONDS. * * Returns: * -1 on failure. * the number of bytes written on success. * * Side effects: * None. * *-------------------------------------------------------------------------- */ ssize_t mongoc_socket_sendv (mongoc_socket_t *sock, /* IN */ mongoc_iovec_t *in_iov, /* IN */ size_t iovcnt, /* IN */ int64_t expire_at) /* IN */ { ssize_t ret = 0; ssize_t sent; size_t cur = 0; mongoc_iovec_t *iov; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (in_iov); BSON_ASSERT (iovcnt); iov = bson_malloc(sizeof(*iov) * iovcnt); memcpy(iov, in_iov, sizeof(*iov) * iovcnt); for (;;) { sent = _mongoc_socket_try_sendv (sock, &iov [cur], iovcnt - cur); TRACE("Sent %ld (of %ld) out of iovcnt=%ld", sent, iov[cur].iov_len, iovcnt); /* * If we failed with anything other than EAGAIN or EWOULDBLOCK, * we should fail immediately as there is another issue with the * underlying socket. */ if (sent == -1) { if (!_mongoc_socket_errno_is_again (sock)) { ret = -1; GOTO(CLEANUP); } } /* * Update internal stream counters. */ if (sent > 0) { ret += sent; mongoc_counter_streams_egress_add (sent); /* * Subtract the sent amount from what we still need to send. */ while ((cur < iovcnt) && (sent >= (ssize_t)iov [cur].iov_len)) { TRACE("still got bytes left: sent -= iov_len: %ld -= %ld", sent, iov[cur+1].iov_len); sent -= iov [cur++].iov_len; } /* * Check if that made us finish all of the iovecs. If so, we are done * sending data over the socket. */ if (cur == iovcnt) { TRACE("%s", "Finished the iovecs"); break; } /* * Increment the current iovec buffer to its proper offset and adjust * the number of bytes to write. */ TRACE("Seeked io_base+%ld", sent); TRACE("Subtracting iov_len -= sent; %ld -= %ld", iov[cur].iov_len, sent); iov [cur].iov_base = ((char *)iov [cur].iov_base) + sent; iov [cur].iov_len -= sent; TRACE("iov_len remaining %ld", iov[cur].iov_len); BSON_ASSERT (iovcnt - cur); BSON_ASSERT (iov [cur].iov_len); } else if (OPERATION_EXPIRED (expire_at)) { GOTO(CLEANUP); } /* * Block on poll() until our desired condition is met. */ if (!_mongoc_socket_wait (sock->sd, POLLOUT, expire_at)) { GOTO(CLEANUP); } } CLEANUP: bson_free(iov); RETURN (ret); } int mongoc_socket_getsockname (mongoc_socket_t *sock, /* IN */ struct sockaddr *addr, /* OUT */ socklen_t *addrlen) /* INOUT */ { int ret; ENTRY; BSON_ASSERT (sock); ret = getsockname (sock->sd, addr, addrlen); _mongoc_socket_capture_errno (sock); RETURN (ret); } char * mongoc_socket_getnameinfo (mongoc_socket_t *sock) /* IN */ { struct sockaddr addr; socklen_t len = sizeof addr; char *ret; char host [BSON_HOST_NAME_MAX + 1]; ENTRY; BSON_ASSERT (sock); if ((0 == getpeername (sock->sd, &addr, &len)) && (0 == getnameinfo (&addr, len, host, sizeof host, NULL, 0, 0))) { ret = bson_strdup (host); RETURN (ret); } RETURN (NULL); } bool mongoc_socket_check_closed (mongoc_socket_t *sock) /* IN */ { bool closed = false; char buf [1]; ssize_t r; if (_mongoc_socket_wait (sock->sd, POLLIN, 0)) { sock->errno_ = 0; r = recv (sock->sd, buf, 1, MSG_PEEK); if (r < 0) { _mongoc_socket_capture_errno (sock); } if (r < 1) { closed = true; } } return closed; } /* * *-------------------------------------------------------------------------- * * mongoc_socket_inet_ntop -- * * Convert the ip from addrinfo into a c string. * * Returns: * The value is returned into 'buffer'. The memory has to be allocated * by the caller * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_socket_inet_ntop (struct addrinfo *rp, /* IN */ char *buf, /* INOUT */ size_t buflen) /* IN */ { void *ptr; char tmp[256]; switch (rp->ai_family) { case AF_INET: ptr = &((struct sockaddr_in *)rp->ai_addr)->sin_addr; inet_ntop (rp->ai_family, ptr, tmp, sizeof (tmp)); bson_snprintf (buf, buflen, "ipv4 %s", tmp); break; case AF_INET6: ptr = &((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr; inet_ntop (rp->ai_family, ptr, tmp, sizeof (tmp)); bson_snprintf (buf, buflen, "ipv6 %s", tmp); break; default: bson_snprintf (buf, buflen, "unknown ip %d", rp->ai_family); break; } } libmongoc-1.3.1/src/mongoc/mongoc-socket.h000066400000000000000000000111751264720626300204740ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_SOCKET_H #define MONGOC_SOCKET_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #ifdef _WIN32 # include # include #else # include # include # include # include # include # include # include # include # include #endif #include "mongoc-iovec.h" BSON_BEGIN_DECLS typedef struct _mongoc_socket_t mongoc_socket_t; typedef struct { mongoc_socket_t *socket; int events; int revents; } mongoc_socket_poll_t; mongoc_socket_t *mongoc_socket_accept (mongoc_socket_t *sock, int64_t expire_at); int mongoc_socket_bind (mongoc_socket_t *sock, const struct sockaddr *addr, socklen_t addrlen); int mongoc_socket_close (mongoc_socket_t *socket); int mongoc_socket_connect (mongoc_socket_t *sock, const struct sockaddr *addr, socklen_t addrlen, int64_t expire_at); char *mongoc_socket_getnameinfo(mongoc_socket_t *sock); void mongoc_socket_destroy (mongoc_socket_t *sock); int mongoc_socket_errno (mongoc_socket_t *sock); int mongoc_socket_getsockname(mongoc_socket_t *sock, struct sockaddr *addr, socklen_t *addrlen); int mongoc_socket_listen (mongoc_socket_t *sock, unsigned int backlog); mongoc_socket_t *mongoc_socket_new (int domain, int type, int protocol); ssize_t mongoc_socket_recv (mongoc_socket_t *sock, void *buf, size_t buflen, int flags, int64_t expire_at); int mongoc_socket_setsockopt (mongoc_socket_t *sock, int level, int optname, const void *optval, socklen_t optlen); ssize_t mongoc_socket_send (mongoc_socket_t *sock, const void *buf, size_t buflen, int64_t expire_at); ssize_t mongoc_socket_sendv (mongoc_socket_t *sock, mongoc_iovec_t *iov, size_t iovcnt, int64_t expire_at); bool mongoc_socket_check_closed (mongoc_socket_t *sock); void mongoc_socket_inet_ntop (struct addrinfo *rp, char *buf, size_t buflen); ssize_t mongoc_socket_poll (mongoc_socket_poll_t *sds, size_t nsds, int32_t timeout); BSON_END_DECLS #endif /* MONGOC_SOCKET_H */ libmongoc-1.3.1/src/mongoc/mongoc-ssl-private.h000066400000000000000000000025641264720626300214570ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_SSL_PRIVATE_H #define MONGOC_SSL_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include #include #include #include "mongoc-ssl.h" BSON_BEGIN_DECLS bool _mongoc_ssl_check_cert (SSL *ssl, const char *host, bool weak_cert_validation); SSL_CTX *_mongoc_ssl_ctx_new (mongoc_ssl_opt_t *opt); char *_mongoc_ssl_extract_subject (const char *filename); void _mongoc_ssl_init (void); void _mongoc_ssl_cleanup (void); BSON_END_DECLS #endif /* MONGOC_SSL_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-ssl.c000066400000000000000000000334741264720626300200060ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-config.h" #ifdef MONGOC_ENABLE_SSL #include #include #include #include #include #include #include #include #include "mongoc-init.h" #include "mongoc-socket.h" #include "mongoc-ssl.h" #include "mongoc-ssl-private.h" #include "mongoc-trace.h" #include "mongoc-thread-private.h" #include "mongoc-util-private.h" /* TODO: we could populate these from a config or something further down the * road for providing defaults */ #ifndef MONGOC_SSL_DEFAULT_TRUST_FILE #define MONGOC_SSL_DEFAULT_TRUST_FILE NULL #endif #ifndef MONGOC_SSL_DEFAULT_TRUST_DIR #define MONGOC_SSL_DEFAULT_TRUST_DIR NULL #endif static mongoc_ssl_opt_t gMongocSslOptDefault = { NULL, NULL, MONGOC_SSL_DEFAULT_TRUST_FILE, MONGOC_SSL_DEFAULT_TRUST_DIR, }; static mongoc_mutex_t * gMongocSslThreadLocks; static void _mongoc_ssl_thread_startup(void); static void _mongoc_ssl_thread_cleanup(void); const mongoc_ssl_opt_t * mongoc_ssl_opt_get_default (void) { return &gMongocSslOptDefault; } /** * _mongoc_ssl_init: * * initialization function for SSL * * This needs to get called early on and is not threadsafe. Called by * mongoc_init. */ void _mongoc_ssl_init (void) { SSL_CTX *ctx; SSL_library_init (); SSL_load_error_strings (); ERR_load_BIO_strings (); OpenSSL_add_all_algorithms (); _mongoc_ssl_thread_startup (); /* * Ensure we also load the ciphers now from the primary thread * or we can run into some weirdness on 64-bit Solaris 10 on * SPARC with openssl 0.9.7. */ ctx = SSL_CTX_new (SSLv23_method ()); if (!ctx) { MONGOC_ERROR ("Failed to initialize OpenSSL."); } SSL_CTX_free (ctx); } void _mongoc_ssl_cleanup (void) { _mongoc_ssl_thread_cleanup (); } static int _mongoc_ssl_password_cb (char *buf, int num, int rwflag, void *user_data) { char *pass = (char *)user_data; int pass_len = (int)strlen (pass); if (num < pass_len + 1) { return 0; } bson_strncpy (buf, pass, num); return pass_len; } /** mongoc_ssl_hostcheck * * rfc 6125 match a given hostname against a given pattern * * Patterns come from DNS common names or subjectAltNames. * * This code is meant to implement RFC 6125 6.4.[1-3] * */ static bool _mongoc_ssl_hostcheck (const char *pattern, const char *hostname) { const char *pattern_label_end; const char *pattern_wildcard; const char *hostname_label_end; size_t prefixlen; size_t suffixlen; pattern_wildcard = strchr (pattern, '*'); if (pattern_wildcard == NULL) { return strcasecmp (pattern, hostname) == 0; } pattern_label_end = strchr (pattern, '.'); /* Bail out on wildcarding in a couple of situations: * o we don't have 2 dots - we're not going to wildcard root tlds * o the wildcard isn't in the left most group (separated by dots) * o the pattern is embedded in an A-label or U-label */ if (pattern_label_end == NULL || strchr (pattern_label_end + 1, '.') == NULL || pattern_wildcard > pattern_label_end || strncasecmp (pattern, "xn--", 4) == 0) { return strcasecmp (pattern, hostname) == 0; } hostname_label_end = strchr (hostname, '.'); /* we know we have a dot in the pattern, we need one in the hostname */ if (hostname_label_end == NULL || strcasecmp (pattern_label_end, hostname_label_end)) { return 0; } /* The wildcard must match at least one character, so the left part of the * hostname is at least as large as the left part of the pattern. */ if ((hostname_label_end - hostname) < (pattern_label_end - pattern)) { return 0; } /* If the left prefix group before the star matches and right of the star * matches... we have a wildcard match */ prefixlen = pattern_wildcard - pattern; suffixlen = pattern_label_end - (pattern_wildcard + 1); return strncasecmp (pattern, hostname, prefixlen) == 0 && strncasecmp (pattern_wildcard + 1, hostname_label_end - suffixlen, suffixlen) == 0; } /** check if a provided cert matches a passed hostname */ bool _mongoc_ssl_check_cert (SSL *ssl, const char *host, bool weak_cert_validation) { X509 *peer; X509_NAME *subject_name; X509_NAME_ENTRY *entry; ASN1_STRING *entry_data; char *check; int length; int idx; int r = 0; long verify_status; size_t addrlen = 0; struct in_addr addr; int i; int n_sans = -1; int target = GEN_DNS; STACK_OF (GENERAL_NAME) * sans = NULL; BSON_ASSERT (ssl); BSON_ASSERT (host); if (weak_cert_validation) { return true; } /** if the host looks like an IP address, match that, otherwise we assume we * have a DNS name */ if (inet_pton (AF_INET, host, &addr)) { target = GEN_IPADD; addrlen = sizeof (struct in_addr); } peer = SSL_get_peer_certificate (ssl); if (!peer) { return false; } verify_status = SSL_get_verify_result (ssl); /** TODO: should we return this somehow? */ if (verify_status == X509_V_OK) { /* get's a stack of alt names that we can iterate through */ sans = (STACK_OF (GENERAL_NAME) *) X509_get_ext_d2i ( (X509 *)peer, NID_subject_alt_name, NULL, NULL); if (sans) { n_sans = sk_GENERAL_NAME_num (sans); /* loop through the stack, or until we find a match */ for (i = 0; i < n_sans && !r; i++) { const GENERAL_NAME *name = sk_GENERAL_NAME_value (sans, i); /* skip entries that can't apply, I.e. IP entries if we've got a * DNS host */ if (name->type == target) { check = (char *)ASN1_STRING_data (name->d.ia5); length = ASN1_STRING_length (name->d.ia5); switch (target) { case GEN_DNS: /* check that we don't have an embedded null byte */ if ((length == bson_strnlen (check, length)) && _mongoc_ssl_hostcheck (check, host)) { r = 1; } break; case GEN_IPADD: if ((length == addrlen) && !memcmp (check, &addr, length)) { r = 1; } break; default: BSON_ASSERT (0); break; } } } GENERAL_NAMES_free (sans); } else { subject_name = X509_get_subject_name (peer); if (subject_name) { idx = -1; i = -1; /* skip to the last common name */ while ((idx = X509_NAME_get_index_by_NID (subject_name, NID_commonName, i)) >= 0) { i = idx; } if (i >= 0) { entry = X509_NAME_get_entry (subject_name, i); entry_data = X509_NAME_ENTRY_get_data (entry); if (entry_data) { /* TODO: I've heard tell that old versions of SSL crap out * when calling ASN1_STRING_to_UTF8 on already utf8 data. * Check up on that */ length = ASN1_STRING_to_UTF8 ((unsigned char **)&check, entry_data); if (length >= 0) { /* check for embedded nulls */ if ((length == bson_strnlen (check, length)) && _mongoc_ssl_hostcheck (check, host)) { r = 1; } OPENSSL_free (check); } } } } } } X509_free (peer); return r; } static bool _mongoc_ssl_setup_ca (SSL_CTX *ctx, const char *cert, const char *cert_dir) { BSON_ASSERT(ctx); BSON_ASSERT(cert || cert_dir); if (!SSL_CTX_load_verify_locations (ctx, cert, cert_dir)) { return 0; } return 1; } static bool _mongoc_ssl_setup_crl (SSL_CTX *ctx, const char *crlfile) { X509_STORE *store; X509_LOOKUP *lookup; int status; store = SSL_CTX_get_cert_store (ctx); X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK); lookup = X509_STORE_add_lookup (store, X509_LOOKUP_file ()); status = X509_load_crl_file (lookup, crlfile, X509_FILETYPE_PEM); return status != 0; } static bool _mongoc_ssl_setup_pem_file (SSL_CTX *ctx, const char *pem_file, const char *password) { if (!SSL_CTX_use_certificate_chain_file (ctx, pem_file)) { return 0; } if (password) { SSL_CTX_set_default_passwd_cb_userdata (ctx, (void *)password); SSL_CTX_set_default_passwd_cb (ctx, _mongoc_ssl_password_cb); } if (!(SSL_CTX_use_PrivateKey_file (ctx, pem_file, SSL_FILETYPE_PEM))) { return 0; } if (!(SSL_CTX_check_private_key (ctx))) { return 0; } return 1; } /** * _mongoc_ssl_ctx_new: * * Create a new ssl context declaratively * * The opt.pem_pwd parameter, if passed, must exist for the life of this * context object (for storing and loading the associated pem file) */ SSL_CTX * _mongoc_ssl_ctx_new (mongoc_ssl_opt_t *opt) { SSL_CTX *ctx = NULL; /* * Ensure we are initialized. This is safe to call multiple times. */ mongoc_init (); ctx = SSL_CTX_new (SSLv23_method ()); BSON_ASSERT (ctx); /* SSL_OP_ALL - Activate all bug workaround options, to support buggy client SSL's. * SSL_OP_NO_SSLv2 - Disable SSL v2 support */ SSL_CTX_set_options (ctx, (SSL_OP_ALL | SSL_OP_NO_SSLv2)); /* HIGH - Enable strong ciphers * !EXPORT - Disable export ciphers (40/56 bit) * !aNULL - Disable anonymous auth ciphers * @STRENGTH - Sort ciphers based on strength */ SSL_CTX_set_cipher_list (ctx, "HIGH:!EXPORT:!aNULL@STRENGTH"); /* If renegotiation is needed, don't return from recv() or send() until it's successful. * Note: this is for blocking sockets only. */ SSL_CTX_set_mode (ctx, SSL_MODE_AUTO_RETRY); /* TODO: does this cargo cult actually matter? * Disable session caching (see SERVER-10261) */ SSL_CTX_set_session_cache_mode (ctx, SSL_SESS_CACHE_OFF); /* Load in verification certs, private keys and revocation lists */ if ((!opt->pem_file || _mongoc_ssl_setup_pem_file (ctx, opt->pem_file, opt->pem_pwd)) && (!(opt->ca_file || opt->ca_dir) || _mongoc_ssl_setup_ca (ctx, opt->ca_file, opt->ca_dir)) && (!opt->crl_file || _mongoc_ssl_setup_crl (ctx, opt->crl_file)) ) { return ctx; } else { SSL_CTX_free (ctx); return NULL; } } char * _mongoc_ssl_extract_subject (const char *filename) { X509_NAME *subject = NULL; X509 *cert = NULL; BIO *certbio = NULL; BIO *strbio = NULL; char *str = NULL; int ret; if (!filename) { return NULL; } certbio = BIO_new (BIO_s_file ()); strbio = BIO_new (BIO_s_mem ());; BSON_ASSERT (certbio); BSON_ASSERT (strbio); BIO_read_filename (certbio, filename); if ((cert = PEM_read_bio_X509 (certbio, NULL, 0, NULL))) { if ((subject = X509_get_subject_name (cert))) { ret = X509_NAME_print_ex (strbio, subject, 0, XN_FLAG_RFC2253); if ((ret > 0) && (ret < INT_MAX)) { str = (char *)bson_malloc (ret + 2); BIO_gets (strbio, str, ret + 1); str [ret] = '\0'; } } } if (cert) { X509_free (cert); } if (certbio) { BIO_free (certbio); } if (strbio) { BIO_free (strbio); } return str; } #ifdef _WIN32 static unsigned long _mongoc_ssl_thread_id_callback (void) { unsigned long ret; ret = (unsigned long)GetCurrentThreadId (); return ret; } #else static unsigned long _mongoc_ssl_thread_id_callback (void) { unsigned long ret; ret = (unsigned long)pthread_self (); return ret; } #endif static void _mongoc_ssl_thread_locking_callback (int mode, int type, const char *file, int line) { if (mode & CRYPTO_LOCK) { mongoc_mutex_lock (&gMongocSslThreadLocks[type]); } else { mongoc_mutex_unlock (&gMongocSslThreadLocks[type]); } } static void _mongoc_ssl_thread_startup (void) { int i; gMongocSslThreadLocks = (mongoc_mutex_t *)OPENSSL_malloc (CRYPTO_num_locks () * sizeof (mongoc_mutex_t)); for (i = 0; i < CRYPTO_num_locks (); i++) { mongoc_mutex_init(&gMongocSslThreadLocks[i]); } if (!CRYPTO_get_locking_callback ()) { CRYPTO_set_locking_callback (_mongoc_ssl_thread_locking_callback); CRYPTO_set_id_callback (_mongoc_ssl_thread_id_callback); } } static void _mongoc_ssl_thread_cleanup (void) { int i; if (CRYPTO_get_locking_callback () == _mongoc_ssl_thread_locking_callback) { CRYPTO_set_locking_callback (NULL); CRYPTO_set_id_callback (NULL); } for (i = 0; i < CRYPTO_num_locks (); i++) { mongoc_mutex_destroy (&gMongocSslThreadLocks[i]); } OPENSSL_free (gMongocSslThreadLocks); } #endif libmongoc-1.3.1/src/mongoc/mongoc-ssl.h000066400000000000000000000022471264720626300200050ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_SSL_H #define MONGOC_SSL_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS typedef struct _mongoc_ssl_opt_t mongoc_ssl_opt_t; struct _mongoc_ssl_opt_t { const char *pem_file; const char *pem_pwd; const char *ca_file; const char *ca_dir; const char *crl_file; bool weak_cert_validation; void *padding [8]; }; const mongoc_ssl_opt_t *mongoc_ssl_opt_get_default (void) BSON_GNUC_CONST; BSON_END_DECLS #endif /* MONGOC_SSL_H */ libmongoc-1.3.1/src/mongoc/mongoc-stream-buffered.c000066400000000000000000000217411264720626300222520ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-buffer-private.h" #include "mongoc-counters-private.h" #include "mongoc-log.h" #include "mongoc-stream-buffered.h" #include "mongoc-stream-private.h" #include "mongoc-trace.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream" typedef struct { mongoc_stream_t stream; mongoc_stream_t *base_stream; mongoc_buffer_t buffer; } mongoc_stream_buffered_t; /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_destroy -- * * Clean up after a mongoc_stream_buffered_t. Free all allocated * resources and release the base stream. * * Returns: * None. * * Side effects: * Everything. * *-------------------------------------------------------------------------- */ static void mongoc_stream_buffered_destroy (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *)stream; BSON_ASSERT (stream); mongoc_stream_destroy(buffered->base_stream); buffered->base_stream = NULL; _mongoc_buffer_destroy (&buffered->buffer); bson_free(stream); mongoc_counter_streams_active_dec(); mongoc_counter_streams_disposed_inc(); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_failed -- * * Called when a stream fails. Useful for streams that differnciate * between failure and cleanup. * Calls mongoc_stream_buffered_destroy() on the stream. * * Returns: * None. * * Side effects: * Everything. * *-------------------------------------------------------------------------- */ static void mongoc_stream_buffered_failed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_destroy (stream); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_close -- * * Close the underlying stream. The buffered content is still * valid. * * Returns: * The return value of mongoc_stream_close() on the underlying * stream. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int mongoc_stream_buffered_close (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *)stream; BSON_ASSERT (stream); return mongoc_stream_close(buffered->base_stream); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_flush -- * * Flushes the underlying stream. * * Returns: * The result of flush on the base stream. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int mongoc_stream_buffered_flush (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *)stream; BSON_ASSERT (buffered); return mongoc_stream_flush(buffered->base_stream); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_writev -- * * Write an iovec to the underlying stream. This write is not * buffered, it passes through to the base stream directly. * * timeout_msec should be the number of milliseconds to wait before * considering the writev as failed. * * Returns: * The number of bytes written or -1 on failure. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static ssize_t mongoc_stream_buffered_writev (mongoc_stream_t *stream, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt, /* IN */ int32_t timeout_msec) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *)stream; ssize_t ret; ENTRY; BSON_ASSERT (buffered); ret = mongoc_stream_writev(buffered->base_stream, iov, iovcnt, timeout_msec); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_readv -- * * Read from the underlying stream. The data will be buffered based * on the buffered streams target buffer size. * * When reading from the underlying stream, we read at least the * requested number of bytes, but try to also fill the stream to * the size of the underlying buffer. * * Note: * This isn't actually a huge savings since we never have more than * one reply waiting for us, but perhaps someday that will be * different. It should help for small replies, however that will * reduce our read() syscalls by 50%. * * Returns: * The number of bytes read or -1 on failure. * * Side effects: * iov[*]->iov_base buffers are filled. * *-------------------------------------------------------------------------- */ static ssize_t mongoc_stream_buffered_readv (mongoc_stream_t *stream, /* IN */ mongoc_iovec_t *iov, /* INOUT */ size_t iovcnt, /* IN */ size_t min_bytes, /* IN */ int32_t timeout_msec) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *)stream; bson_error_t error = { 0 }; size_t total_bytes = 0; size_t i; ENTRY; BSON_ASSERT (buffered); for (i = 0; i < iovcnt; i++) { total_bytes += iov[i].iov_len; } if (-1 == _mongoc_buffer_fill (&buffered->buffer, buffered->base_stream, total_bytes, timeout_msec, &error)) { MONGOC_WARNING ("Failure to buffer %u bytes: %s", (unsigned)total_bytes, error.message); RETURN (-1); } BSON_ASSERT (buffered->buffer.len >= total_bytes); for (i = 0; i < iovcnt; i++) { memcpy(iov[i].iov_base, buffered->buffer.data + buffered->buffer.off, iov[i].iov_len); buffered->buffer.off += iov[i].iov_len; buffered->buffer.len -= iov[i].iov_len; } RETURN (total_bytes); } static mongoc_stream_t * _mongoc_stream_buffered_get_base_stream (mongoc_stream_t *stream) /* IN */ { return ((mongoc_stream_buffered_t *)stream)->base_stream; } static bool _mongoc_stream_buffered_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *)stream; BSON_ASSERT (stream); return mongoc_stream_check_closed (buffered->base_stream); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_new -- * * Creates a new mongoc_stream_buffered_t. * * This stream will read from an underlying stream and try to read * more data than necessary. It can help lower the number of read() * or recv() syscalls performed. * * @base_stream is considered owned by the resulting stream after * calling this function. * * Returns: * A newly allocated mongoc_stream_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_stream_buffered_new (mongoc_stream_t *base_stream, /* IN */ size_t buffer_size) /* IN */ { mongoc_stream_buffered_t *stream; BSON_ASSERT (base_stream); stream = (mongoc_stream_buffered_t *)bson_malloc0(sizeof *stream); stream->stream.type = MONGOC_STREAM_BUFFERED; stream->stream.destroy = mongoc_stream_buffered_destroy; stream->stream.failed = mongoc_stream_buffered_failed; stream->stream.close = mongoc_stream_buffered_close; stream->stream.flush = mongoc_stream_buffered_flush; stream->stream.writev = mongoc_stream_buffered_writev; stream->stream.readv = mongoc_stream_buffered_readv; stream->stream.get_base_stream = _mongoc_stream_buffered_get_base_stream; stream->stream.check_closed = _mongoc_stream_buffered_check_closed; stream->base_stream = base_stream; _mongoc_buffer_init (&stream->buffer, NULL, buffer_size, NULL, NULL); mongoc_counter_streams_active_inc(); return (mongoc_stream_t *)stream; } libmongoc-1.3.1/src/mongoc/mongoc-stream-buffered.h000066400000000000000000000020441264720626300222520ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_STREAM_BUFFERED_H #define MONGOC_STREAM_BUFFERED_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-stream.h" BSON_BEGIN_DECLS mongoc_stream_t *mongoc_stream_buffered_new (mongoc_stream_t *base_stream, size_t buffer_size); BSON_END_DECLS #endif /* MONGOC_STREAM_BUFFERED_H */ libmongoc-1.3.1/src/mongoc/mongoc-stream-file.c000066400000000000000000000117351264720626300214110ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef _WIN32 # include # include #endif #include "mongoc-stream-private.h" #include "mongoc-stream-file.h" #include "mongoc-trace.h" /* * TODO: This does not respect timeouts or set O_NONBLOCK. * But that should be fine until it isn't :-) */ struct _mongoc_stream_file_t { mongoc_stream_t vtable; int fd; }; static int _mongoc_stream_file_close (mongoc_stream_t *stream) { mongoc_stream_file_t *file = (mongoc_stream_file_t *)stream; int ret; ENTRY; BSON_ASSERT (file); if (file->fd != -1) { #ifdef _WIN32 ret = _close (file->fd); #else ret = close (file->fd); #endif file->fd = -1; RETURN (ret); } RETURN (0); } static void _mongoc_stream_file_destroy (mongoc_stream_t *stream) { mongoc_stream_file_t *file = (mongoc_stream_file_t *)stream; ENTRY; BSON_ASSERT (file); if (file->fd) { _mongoc_stream_file_close (stream); } bson_free (file); EXIT; } static void _mongoc_stream_file_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_stream_file_destroy (stream); EXIT; } static int _mongoc_stream_file_flush (mongoc_stream_t *stream) /* IN */ { mongoc_stream_file_t *file = (mongoc_stream_file_t *)stream; BSON_ASSERT (file); if (file->fd != -1) { #ifdef _WIN32 return _commit (file->fd); #else return fsync (file->fd); #endif } return 0; } static ssize_t _mongoc_stream_file_readv (mongoc_stream_t *stream, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt, /* IN */ size_t min_bytes, /* IN */ int32_t timeout_msec) /* IN */ { mongoc_stream_file_t *file = (mongoc_stream_file_t *)stream; ssize_t ret = 0; #ifdef _WIN32 ssize_t nread; size_t i; ENTRY; for (i = 0; i < iovcnt; i++) { nread = _read (file->fd, iov [i].iov_base, iov [i].iov_len); if (nread < 0) { RETURN (ret ? ret : -1); } else if (nread == 0) { RETURN (ret ? ret : 0); } else { ret += nread; if (nread != iov[i].iov_len) { RETURN (ret ? ret : -1); } } } RETURN (ret); #else ENTRY; ret = readv (file->fd, iov, (int) iovcnt); RETURN (ret); #endif } static ssize_t _mongoc_stream_file_writev (mongoc_stream_t *stream, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt, /* IN */ int32_t timeout_msec) /* IN */ { mongoc_stream_file_t *file = (mongoc_stream_file_t *)stream; #ifdef _WIN32 ssize_t ret = 0; ssize_t nwrite; size_t i; for (i = 0; i < iovcnt; i++) { nwrite = _write (file->fd, iov [i].iov_base, iov [i].iov_len); if (nwrite != iov [i].iov_len) { return ret ? ret : -1; } ret += nwrite; } return ret; #else return writev (file->fd, iov, (int) iovcnt); #endif } static bool _mongoc_stream_file_check_closed (mongoc_stream_t *stream) /* IN */ { return false; } mongoc_stream_t * mongoc_stream_file_new (int fd) /* IN */ { mongoc_stream_file_t *stream; BSON_ASSERT (fd != -1); stream = (mongoc_stream_file_t *)bson_malloc0 (sizeof *stream); stream->vtable.type = MONGOC_STREAM_FILE; stream->vtable.close = _mongoc_stream_file_close; stream->vtable.destroy = _mongoc_stream_file_destroy; stream->vtable.failed = _mongoc_stream_file_failed; stream->vtable.flush = _mongoc_stream_file_flush; stream->vtable.readv = _mongoc_stream_file_readv; stream->vtable.writev = _mongoc_stream_file_writev; stream->vtable.check_closed = _mongoc_stream_file_check_closed; stream->fd = fd; return (mongoc_stream_t *)stream; } mongoc_stream_t * mongoc_stream_file_new_for_path (const char *path, /* IN */ int flags, /* IN */ int mode) /* IN */ { int fd = -1; BSON_ASSERT (path); #ifdef _WIN32 if (_sopen_s (&fd, path, (flags | _O_BINARY), _SH_DENYNO, mode) != 0) { fd = -1; } #else fd = open (path, flags, mode); #endif if (fd == -1) { return NULL; } return mongoc_stream_file_new (fd); } int mongoc_stream_file_get_fd (mongoc_stream_file_t *stream) { BSON_ASSERT (stream); return stream->fd; } libmongoc-1.3.1/src/mongoc/mongoc-stream-file.h000066400000000000000000000024651264720626300214160ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_STREAM_FILE_H #define MONGOC_STREAM_FILE_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include "mongoc-stream.h" BSON_BEGIN_DECLS typedef struct _mongoc_stream_file_t mongoc_stream_file_t; mongoc_stream_t *mongoc_stream_file_new (int fd); mongoc_stream_t *mongoc_stream_file_new_for_path (const char *path, int flags, int mode); int mongoc_stream_file_get_fd (mongoc_stream_file_t *stream); BSON_END_DECLS #endif /* MONGOC_STREAM_FILE_H */ libmongoc-1.3.1/src/mongoc/mongoc-stream-gridfs.c000066400000000000000000000100311264720626300217340ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-counters-private.h" #include "mongoc-stream.h" #include "mongoc-stream-private.h" #include "mongoc-gridfs-file.h" #include "mongoc-gridfs-file-private.h" #include "mongoc-trace.h" #include "mongoc-stream-gridfs.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-gridfs" typedef struct { mongoc_stream_t stream; mongoc_gridfs_file_t *file; } mongoc_stream_gridfs_t; static void _mongoc_stream_gridfs_destroy (mongoc_stream_t *stream) { ENTRY; BSON_ASSERT (stream); mongoc_stream_close (stream); bson_free (stream); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); EXIT; } static void _mongoc_stream_gridfs_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_stream_gridfs_destroy (stream); EXIT; } static int _mongoc_stream_gridfs_close (mongoc_stream_t *stream) { mongoc_stream_gridfs_t *gridfs = (mongoc_stream_gridfs_t *)stream; int ret = 0; ENTRY; BSON_ASSERT (stream); ret = mongoc_gridfs_file_save (gridfs->file); RETURN (ret); } static int _mongoc_stream_gridfs_flush (mongoc_stream_t *stream) { mongoc_stream_gridfs_t *gridfs = (mongoc_stream_gridfs_t *)stream; int ret = 0; ENTRY; BSON_ASSERT (stream); ret = mongoc_gridfs_file_save (gridfs->file); RETURN (ret); } static ssize_t _mongoc_stream_gridfs_readv (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_stream_gridfs_t *file = (mongoc_stream_gridfs_t *)stream; ssize_t ret = 0; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (timeout_msec <= INT_MAX); ret = mongoc_gridfs_file_readv (file->file, iov, iovcnt, min_bytes, timeout_msec); mongoc_counter_streams_ingress_add (ret); RETURN (ret); } static ssize_t _mongoc_stream_gridfs_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_stream_gridfs_t *file = (mongoc_stream_gridfs_t *)stream; ssize_t ret = 0; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); ret = mongoc_gridfs_file_writev (file->file, iov, iovcnt, timeout_msec); if (!ret) { RETURN (ret); } mongoc_counter_streams_egress_add (ret); RETURN (ret); } static bool _mongoc_stream_gridfs_check_closed (mongoc_stream_t *stream) /* IN */ { return false; } mongoc_stream_t * mongoc_stream_gridfs_new (mongoc_gridfs_file_t *file) { mongoc_stream_gridfs_t *stream; ENTRY; BSON_ASSERT (file); stream = (mongoc_stream_gridfs_t *)bson_malloc0 (sizeof *stream); stream->file = file; stream->stream.type = MONGOC_STREAM_GRIDFS; stream->stream.destroy = _mongoc_stream_gridfs_destroy; stream->stream.failed = _mongoc_stream_gridfs_failed; stream->stream.close = _mongoc_stream_gridfs_close; stream->stream.flush = _mongoc_stream_gridfs_flush; stream->stream.writev = _mongoc_stream_gridfs_writev; stream->stream.readv = _mongoc_stream_gridfs_readv; stream->stream.check_closed = _mongoc_stream_gridfs_check_closed; mongoc_counter_streams_active_inc (); RETURN ((mongoc_stream_t *)stream); } libmongoc-1.3.1/src/mongoc/mongoc-stream-gridfs.h000066400000000000000000000017511264720626300217520ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_STREAM_GRIDFS_H #define MONGOC_STREAM_GRIDFS_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-gridfs.h" #include "mongoc-stream.h" BSON_BEGIN_DECLS mongoc_stream_t *mongoc_stream_gridfs_new (mongoc_gridfs_file_t *file); BSON_END_DECLS #endif /* MONGOC_STREAM_GRIDFS_H */ libmongoc-1.3.1/src/mongoc/mongoc-stream-private.h000066400000000000000000000026561264720626300221530ustar00rootroot00000000000000/* * Copyright 2013-2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_STREAM_PRIVATE_H #define MONGOC_STREAM_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include "mongoc-iovec.h" #include "mongoc-stream.h" BSON_BEGIN_DECLS #define MONGOC_STREAM_SOCKET 1 #define MONGOC_STREAM_FILE 2 #define MONGOC_STREAM_BUFFERED 3 #define MONGOC_STREAM_GRIDFS 4 #define MONGOC_STREAM_TLS 5 bool mongoc_stream_wait (mongoc_stream_t *stream, int64_t expire_at); bool _mongoc_stream_writev_full (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_STREAM_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-stream-socket.c000066400000000000000000000160011264720626300217510ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-stream-private.h" #include "mongoc-stream-socket.h" #include "mongoc-trace.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream" struct _mongoc_stream_socket_t { mongoc_stream_t vtable; mongoc_socket_t *sock; }; static BSON_INLINE int64_t get_expiration (int32_t timeout_msec) { if (timeout_msec < 0) { return -1; } else if (timeout_msec == 0) { return 0; } else { return (bson_get_monotonic_time () + ((int64_t)timeout_msec * 1000L)); } } static int _mongoc_stream_socket_close (mongoc_stream_t *stream) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *)stream; int ret; ENTRY; BSON_ASSERT (ss); if (ss->sock) { ret = mongoc_socket_close (ss->sock); RETURN (ret); } RETURN (0); } static void _mongoc_stream_socket_destroy (mongoc_stream_t *stream) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *)stream; ENTRY; BSON_ASSERT (ss); if (ss->sock) { mongoc_socket_destroy (ss->sock); ss->sock = NULL; } bson_free (ss); EXIT; } static void _mongoc_stream_socket_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_stream_socket_destroy (stream); EXIT; } static int _mongoc_stream_socket_setsockopt (mongoc_stream_t *stream, int level, int optname, void *optval, socklen_t optlen) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *)stream; int ret; ENTRY; BSON_ASSERT (ss); BSON_ASSERT (ss->sock); ret = mongoc_socket_setsockopt (ss->sock, level, optname, optval, optlen); RETURN (ret); } static int _mongoc_stream_socket_flush (mongoc_stream_t *stream) { ENTRY; RETURN (0); } static ssize_t _mongoc_stream_socket_readv (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *)stream; int64_t expire_at; ssize_t ret = 0; ssize_t nread; size_t cur = 0; ENTRY; BSON_ASSERT (ss); BSON_ASSERT (ss->sock); expire_at = get_expiration (timeout_msec); /* * This isn't ideal, we should plumb through to recvmsg(), but we * don't actually use this in any way but to a single buffer * currently anyway, so should be just fine. */ for (;;) { nread = mongoc_socket_recv (ss->sock, iov [cur].iov_base, iov [cur].iov_len, 0, expire_at); if (nread <= 0) { if (ret >= (ssize_t)min_bytes) { RETURN (ret); } errno = mongoc_socket_errno (ss->sock); RETURN (-1); } ret += nread; while ((cur < iovcnt) && (nread >= (ssize_t)iov [cur].iov_len)) { nread -= iov [cur++].iov_len; } if (cur == iovcnt) { break; } if (ret >= (ssize_t)min_bytes) { RETURN (ret); } iov [cur].iov_base = ((char *)iov [cur].iov_base) + nread; iov [cur].iov_len -= nread; BSON_ASSERT (iovcnt - cur); BSON_ASSERT (iov [cur].iov_len); } RETURN (ret); } static ssize_t _mongoc_stream_socket_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *)stream; int64_t expire_at; ssize_t ret; ENTRY; if (ss->sock) { expire_at = get_expiration (timeout_msec); ret = mongoc_socket_sendv (ss->sock, iov, iovcnt, expire_at); errno = mongoc_socket_errno (ss->sock); RETURN (ret); } RETURN (-1); } static ssize_t _mongoc_stream_socket_poll (mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeout_msec) { int i; ssize_t ret = -1; mongoc_socket_poll_t *sds; mongoc_stream_socket_t *ss; ENTRY; sds = (mongoc_socket_poll_t *)bson_malloc(sizeof(*sds) * nstreams); for (i = 0; i < nstreams; i++) { ss = (mongoc_stream_socket_t *)streams[i].stream; if (! ss->sock) { goto CLEANUP; } sds[i].socket = ss->sock; sds[i].events = streams[i].events; } ret = mongoc_socket_poll(sds, nstreams, timeout_msec); if (ret > 0) { for (i = 0; i < nstreams; i++) { streams[i].revents = sds[i].revents; } } CLEANUP: bson_free(sds); RETURN (ret); } mongoc_socket_t * mongoc_stream_socket_get_socket (mongoc_stream_socket_t *stream) /* IN */ { BSON_ASSERT (stream); return stream->sock; } static bool _mongoc_stream_socket_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *)stream; ENTRY; BSON_ASSERT (stream); if (ss->sock) { RETURN (mongoc_socket_check_closed (ss->sock)); } RETURN (true); } /* *-------------------------------------------------------------------------- * * mongoc_stream_socket_new -- * * Create a new mongoc_stream_t using the mongoc_socket_t for * read and write underneath. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_stream_socket_new (mongoc_socket_t *sock) /* IN */ { mongoc_stream_socket_t *stream; BSON_ASSERT (sock); stream = (mongoc_stream_socket_t *)bson_malloc0 (sizeof *stream); stream->vtable.type = MONGOC_STREAM_SOCKET; stream->vtable.close = _mongoc_stream_socket_close; stream->vtable.destroy = _mongoc_stream_socket_destroy; stream->vtable.failed = _mongoc_stream_socket_failed; stream->vtable.flush = _mongoc_stream_socket_flush; stream->vtable.readv = _mongoc_stream_socket_readv; stream->vtable.writev = _mongoc_stream_socket_writev; stream->vtable.setsockopt = _mongoc_stream_socket_setsockopt; stream->vtable.check_closed = _mongoc_stream_socket_check_closed; stream->vtable.poll = _mongoc_stream_socket_poll; stream->sock = sock; return (mongoc_stream_t *)stream; } libmongoc-1.3.1/src/mongoc/mongoc-stream-socket.h000066400000000000000000000021661264720626300217650ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_STREAM_SOCKET_H #define MONGOC_STREAM_SOCKET_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include "mongoc-socket.h" #include "mongoc-stream.h" BSON_BEGIN_DECLS typedef struct _mongoc_stream_socket_t mongoc_stream_socket_t; mongoc_stream_t *mongoc_stream_socket_new (mongoc_socket_t *socket); mongoc_socket_t *mongoc_stream_socket_get_socket (mongoc_stream_socket_t *stream); BSON_END_DECLS #endif /* MONGOC_STREAM_SOCKET_H */ libmongoc-1.3.1/src/mongoc/mongoc-stream-tls.c000066400000000000000000000565031264720626300212760ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-config.h" #ifdef MONGOC_ENABLE_SSL #include #include #include #include #include #include #ifdef _WIN32 # include # include #endif #include "mongoc-counters-private.h" #include "mongoc-errno-private.h" #include "mongoc-stream-tls.h" #include "mongoc-stream-private.h" #include "mongoc-ssl-private.h" #include "mongoc-trace.h" #include "mongoc-log.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-tls" #define MONGOC_STREAM_TLS_BUFFER_SIZE 4096 /** * mongoc_stream_tls_t: * * Private storage for handling callbacks from mongoc_stream and BIO_* * * The one funny wrinkle comes with timeout, which we use statefully to * statefully pass timeouts through from the mongoc-stream api. * * TODO: is there a cleaner way to manage that? */ typedef struct { mongoc_stream_t parent; mongoc_stream_t *base_stream; BIO *bio; SSL_CTX *ctx; int32_t timeout_msec; bool weak_cert_validation; } mongoc_stream_tls_t; static int _mongoc_stream_tls_bio_create (BIO *b); static int _mongoc_stream_tls_bio_destroy (BIO *b); static int _mongoc_stream_tls_bio_read (BIO *b, char *buf, int len); static int _mongoc_stream_tls_bio_write (BIO *b, const char *buf, int len); static long _mongoc_stream_tls_bio_ctrl (BIO *b, int cmd, long num, void *ptr); static int _mongoc_stream_tls_bio_gets (BIO *b, char *buf, int len); static int _mongoc_stream_tls_bio_puts (BIO *b, const char *str); /* Magic vtable to make our BIO shim */ static BIO_METHOD gMongocStreamTlsRawMethods = { BIO_TYPE_FILTER, "mongoc-stream-tls-glue", _mongoc_stream_tls_bio_write, _mongoc_stream_tls_bio_read, _mongoc_stream_tls_bio_puts, _mongoc_stream_tls_bio_gets, _mongoc_stream_tls_bio_ctrl, _mongoc_stream_tls_bio_create, _mongoc_stream_tls_bio_destroy }; /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_bio_create -- * * BIO callback to create a new BIO instance. * * Returns: * 1 if successful. * * Side effects: * @b is initialized. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_bio_create (BIO *b) { BSON_ASSERT (b); b->init = 1; b->num = 0; b->ptr = NULL; b->flags = 0; return 1; } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_bio_destroy -- * * Release resources associated with BIO. * * Returns: * 1 if successful. * * Side effects: * @b is destroyed. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_bio_destroy (BIO *b) { mongoc_stream_tls_t *tls; BSON_ASSERT (b); tls = (mongoc_stream_tls_t *)b->ptr; if (!tls) { return -1; } b->ptr = NULL; b->init = 0; b->flags = 0; tls->bio = NULL; return 1; } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_bio_read -- * * Read from the underlying stream to BIO. * * Returns: * -1 on failure; otherwise the number of bytes read. * * Side effects: * @buf is filled with data read from underlying stream. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_bio_read (BIO *b, char *buf, int len) { mongoc_stream_tls_t *tls; int ret; BSON_ASSERT (b); BSON_ASSERT (buf); ENTRY; tls = (mongoc_stream_tls_t *)b->ptr; if (!tls) { RETURN (-1); } errno = 0; ret = (int)mongoc_stream_read (tls->base_stream, buf, len, 0, tls->timeout_msec); BIO_clear_retry_flags (b); if ((ret <= 0) && MONGOC_ERRNO_IS_AGAIN (errno)) { BIO_set_retry_read (b); } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_bio_write -- * * Write to the underlying stream on behalf of BIO. * * Returns: * -1 on failure; otherwise the number of bytes written. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_bio_write (BIO *b, const char *buf, int len) { mongoc_stream_tls_t *tls; mongoc_iovec_t iov; int ret; ENTRY; BSON_ASSERT (b); BSON_ASSERT (buf); tls = (mongoc_stream_tls_t *)b->ptr; if (!tls) { RETURN (-1); } iov.iov_base = (void *)buf; iov.iov_len = len; errno = 0; TRACE("mongoc_stream_writev is expected to write: %d", len); ret = (int)mongoc_stream_writev (tls->base_stream, &iov, 1, tls->timeout_msec); BIO_clear_retry_flags (b); if (len > ret) { TRACE("Returned short write: %d of %d", ret, len); } else { TRACE("Completed the %d", ret); } if (ret <= 0 && MONGOC_ERRNO_IS_AGAIN (errno)) { TRACE("%s", "Requesting a retry"); BIO_set_retry_write (b); } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_bio_ctrl -- * * Handle ctrl callback for BIO. * * Returns: * ioctl dependent. * * Side effects: * ioctl dependent. * *-------------------------------------------------------------------------- */ static long _mongoc_stream_tls_bio_ctrl (BIO *b, int cmd, long num, void *ptr) { switch (cmd) { case BIO_CTRL_FLUSH: return 1; default: return 0; } } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_bio_gets -- * * BIO callback for gets(). Not supported. * * Returns: * -1 always. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_bio_gets (BIO *b, char *buf, int len) { return -1; } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_bio_puts -- * * BIO callback to perform puts(). Just calls the actual write * callback. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_bio_puts (BIO *b, const char *str) { return _mongoc_stream_tls_bio_write (b, str, (int)strlen (str)); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_destroy -- * * Cleanup after usage of a mongoc_stream_tls_t. Free all allocated * resources and ensure connections are closed. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _mongoc_stream_tls_destroy (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; BSON_ASSERT (tls); BIO_free_all (tls->bio); tls->bio = NULL; mongoc_stream_destroy (tls->base_stream); tls->base_stream = NULL; SSL_CTX_free (tls->ctx); tls->ctx = NULL; bson_free (stream); mongoc_counter_streams_active_dec(); mongoc_counter_streams_disposed_inc(); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_failed -- * * Called on stream failure. Same as _mongoc_stream_tls_destroy() * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _mongoc_stream_tls_failed (mongoc_stream_t *stream) { _mongoc_stream_tls_destroy (stream); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_close -- * * Close the underlying socket. * * Linus dictates that you should not check the result of close() * since there is a race condition with EAGAIN and a new file * descriptor being opened. * * Returns: * 0 on success; otherwise -1. * * Side effects: * The BIO fd is closed. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_close (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; int ret = 0; ENTRY; BSON_ASSERT (tls); ret = mongoc_stream_close (tls->base_stream); RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_flush -- * * Flush the underlying stream. * * Returns: * 0 if successful; otherwise -1. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_flush (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; BSON_ASSERT (tls); return BIO_flush (tls->bio); } static ssize_t _mongoc_stream_tls_write (mongoc_stream_tls_t *tls, char *buf, size_t buf_len) { ssize_t ret; int64_t now; int64_t expire = 0; ENTRY; BSON_ASSERT (tls); BSON_ASSERT (buf); BSON_ASSERT (buf_len); if (tls->timeout_msec >= 0) { expire = bson_get_monotonic_time () + (tls->timeout_msec * 1000UL); } ret = BIO_write (tls->bio, buf, buf_len); TRACE("BIO_write returned %ld", ret); TRACE("I got ret: %ld and retry: %d", ret, BIO_should_retry (tls->bio)); if (ret <= 0) { return ret; } if (expire) { now = bson_get_monotonic_time (); if ((expire - now) < 0) { if (ret < buf_len) { mongoc_counter_streams_timeout_inc(); } tls->timeout_msec = 0; } else { tls->timeout_msec = (expire - now) / 1000L; } } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_writev -- * * Write the iovec to the stream. This function will try to write * all of the bytes or fail. If the number of bytes is not equal * to the number requested, a failure or EOF has occurred. * * Returns: * -1 on failure, otherwise the number of bytes written. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static ssize_t _mongoc_stream_tls_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; char buf[MONGOC_STREAM_TLS_BUFFER_SIZE]; ssize_t ret = 0; ssize_t child_ret; size_t i; size_t iov_pos = 0; /* There's a bit of a dance to coalesce vectorized writes into * MONGOC_STREAM_TLS_BUFFER_SIZE'd writes to avoid lots of small tls * packets. * * The basic idea is that we want to combine writes in the buffer if they're * smaller than the buffer, flushing as it gets full. For larger writes, or * the last write in the iovec array, we want to ignore the buffer and just * write immediately. We take care of doing buffer writes by re-invoking * ourself with a single iovec_t, pointing at our stack buffer. */ char *buf_head = buf; char *buf_tail = buf; char *buf_end = buf + MONGOC_STREAM_TLS_BUFFER_SIZE; size_t bytes; char *to_write = NULL; size_t to_write_len; BSON_ASSERT (tls); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); ENTRY; tls->timeout_msec = timeout_msec; for (i = 0; i < iovcnt; i++) { iov_pos = 0; while (iov_pos < iov[i].iov_len) { if (buf_head != buf_tail || ((i + 1 < iovcnt) && ((buf_end - buf_tail) > (iov[i].iov_len - iov_pos)))) { /* If we have either of: * - buffered bytes already * - another iovec to send after this one and we don't have more * bytes to send than the size of the buffer. * * copy into the buffer */ bytes = BSON_MIN (iov[i].iov_len - iov_pos, buf_end - buf_tail); memcpy (buf_tail, (char *) iov[i].iov_base + iov_pos, bytes); buf_tail += bytes; iov_pos += bytes; if (buf_tail == buf_end) { /* If we're full, request send */ to_write = buf_head; to_write_len = buf_tail - buf_head; buf_tail = buf_head = buf; } } else { /* Didn't buffer, so just write it through */ to_write = (char *)iov[i].iov_base + iov_pos; to_write_len = iov[i].iov_len - iov_pos; iov_pos += to_write_len; } if (to_write) { /* We get here if we buffered some bytes and filled the buffer, or * if we didn't buffer and have to send out of the iovec */ child_ret = _mongoc_stream_tls_write (tls, to_write, to_write_len); if (child_ret != to_write_len) { TRACE("Got child_ret: %ld while to_write_len is: %ld", child_ret, to_write_len); } if (child_ret < 0) { TRACE("Returning what I had (%ld) as apposed to the error (%ld, errno:%d)", ret, child_ret, errno); RETURN (ret); } ret += child_ret; if (child_ret < to_write_len) { /* we timed out, so send back what we could send */ RETURN (ret); } to_write = NULL; } } } if (buf_head != buf_tail) { /* If we have any bytes buffered, send */ child_ret = _mongoc_stream_tls_write (tls, buf_head, buf_tail - buf_head); if (child_ret < 0) { RETURN (child_ret); } ret += child_ret; } if (ret >= 0) { mongoc_counter_streams_egress_add (ret); } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_readv -- * * Read from the stream into iov. This function will try to read * all of the bytes or fail. If the number of bytes is not equal * to the number requested, a failure or EOF has occurred. * * Returns: * -1 on failure, 0 on EOF, otherwise the number of bytes read. * * Side effects: * iov buffers will be written to. * *-------------------------------------------------------------------------- */ static ssize_t _mongoc_stream_tls_readv (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; ssize_t ret = 0; size_t i; int read_ret; size_t iov_pos = 0; int64_t now; int64_t expire = 0; ENTRY; BSON_ASSERT (tls); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); tls->timeout_msec = timeout_msec; if (timeout_msec >= 0) { expire = bson_get_monotonic_time () + (timeout_msec * 1000UL); } for (i = 0; i < iovcnt; i++) { iov_pos = 0; while (iov_pos < iov[i].iov_len) { read_ret = BIO_read (tls->bio, (char *)iov[i].iov_base + iov_pos, (int)(iov[i].iov_len - iov_pos)); /* https://www.openssl.org/docs/crypto/BIO_should_retry.html: * * If BIO_should_retry() returns false then the precise "error * condition" depends on the BIO type that caused it and the return * code of the BIO operation. For example if a call to BIO_read() on a * socket BIO returns 0 and BIO_should_retry() is false then the cause * will be that the connection closed. */ if (read_ret < 0 || (read_ret == 0 && !BIO_should_retry (tls->bio))) { return -1; } if (expire) { now = bson_get_monotonic_time (); if ((expire - now) < 0) { if (read_ret == 0) { mongoc_counter_streams_timeout_inc(); #ifdef _WIN32 errno = WSAETIMEDOUT; #else errno = ETIMEDOUT; #endif RETURN (-1); } tls->timeout_msec = 0; } else { tls->timeout_msec = (expire - now) / 1000L; } } ret += read_ret; if ((size_t)ret >= min_bytes) { mongoc_counter_streams_ingress_add(ret); RETURN (ret); } iov_pos += read_ret; } } if (ret >= 0) { mongoc_counter_streams_ingress_add(ret); } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_setsockopt -- * * Perform a setsockopt on the underlying stream. * * Returns: * -1 on failure, otherwise opt specific value. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_setsockopt (mongoc_stream_t *stream, int level, int optname, void *optval, socklen_t optlen) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; BSON_ASSERT (tls); return mongoc_stream_setsockopt (tls->base_stream, level, optname, optval, optlen); } /** * mongoc_stream_tls_do_handshake: * * force an ssl handshake * * This will happen on the first read or write otherwise */ bool mongoc_stream_tls_do_handshake (mongoc_stream_t *stream, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; BSON_ASSERT (tls); tls->timeout_msec = timeout_msec; if (BIO_do_handshake (tls->bio) == 1) { return true; } if (!timeout_msec) { return false; } if (!errno) { #ifdef _WIN32 errno = WSAETIMEDOUT; #else errno = ETIMEDOUT; #endif } return false; } /** * mongoc_stream_tls_should_retry: * * If the stream should be retried */ bool mongoc_stream_tls_should_retry (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; BSON_ASSERT (tls); return BIO_should_retry (tls->bio); } /** * mongoc_stream_tls_should_read: * * If the stream should read */ bool mongoc_stream_tls_should_read (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; BSON_ASSERT (tls); return BIO_should_read (tls->bio); } /** * mongoc_stream_tls_should_write: * * If the stream should write */ bool mongoc_stream_tls_should_write (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; BSON_ASSERT (tls); return BIO_should_write (tls->bio); } /** * mongoc_stream_tls_check_cert: * * check the cert returned by the other party */ bool mongoc_stream_tls_check_cert (mongoc_stream_t *stream, const char *host) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; SSL *ssl; BSON_ASSERT (tls); BSON_ASSERT (host); BIO_get_ssl (tls->bio, &ssl); return _mongoc_ssl_check_cert (ssl, host, tls->weak_cert_validation); } static mongoc_stream_t * _mongoc_stream_tls_get_base_stream (mongoc_stream_t *stream) { return ((mongoc_stream_tls_t *)stream)->base_stream; } static bool _mongoc_stream_tls_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *)stream; BSON_ASSERT (stream); return mongoc_stream_check_closed (tls->base_stream); } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_new -- * * Creates a new mongoc_stream_tls_t to communicate with a remote * server using a TLS stream. * * @base_stream should be a stream that will become owned by the * resulting tls stream. It will be used for raw I/O. * * @trust_store_dir should be a path to the SSL cert db to use for * verifying trust of the remote server. * * Returns: * NULL on failure, otherwise a mongoc_stream_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_stream_tls_new (mongoc_stream_t *base_stream, mongoc_ssl_opt_t *opt, int client) { mongoc_stream_tls_t *tls; SSL_CTX *ssl_ctx = NULL; BIO *bio_ssl = NULL; BIO *bio_mongoc_shim = NULL; BSON_ASSERT(base_stream); BSON_ASSERT(opt); ssl_ctx = _mongoc_ssl_ctx_new (opt); if (!ssl_ctx) { return NULL; } bio_ssl = BIO_new_ssl (ssl_ctx, client); if (!bio_ssl) { return NULL; } bio_mongoc_shim = BIO_new (&gMongocStreamTlsRawMethods); if (!bio_mongoc_shim) { BIO_free_all (bio_ssl); return NULL; } BIO_push (bio_ssl, bio_mongoc_shim); tls = (mongoc_stream_tls_t *)bson_malloc0 (sizeof *tls); tls->base_stream = base_stream; tls->parent.type = MONGOC_STREAM_TLS; tls->parent.destroy = _mongoc_stream_tls_destroy; tls->parent.failed = _mongoc_stream_tls_failed; tls->parent.close = _mongoc_stream_tls_close; tls->parent.flush = _mongoc_stream_tls_flush; tls->parent.writev = _mongoc_stream_tls_writev; tls->parent.readv = _mongoc_stream_tls_readv; tls->parent.setsockopt = _mongoc_stream_tls_setsockopt; tls->parent.get_base_stream = _mongoc_stream_tls_get_base_stream; tls->parent.check_closed = _mongoc_stream_tls_check_closed; tls->weak_cert_validation = opt->weak_cert_validation; tls->bio = bio_ssl; tls->ctx = ssl_ctx; tls->timeout_msec = -1; bio_mongoc_shim->ptr = tls; mongoc_counter_streams_active_inc(); return (mongoc_stream_t *)tls; } #endif libmongoc-1.3.1/src/mongoc/mongoc-stream-tls.h000066400000000000000000000032321264720626300212720ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_STREAM_TLS_H #define MONGOC_STREAM_TLS_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-ssl.h" #include "mongoc-stream.h" BSON_BEGIN_DECLS bool mongoc_stream_tls_do_handshake (mongoc_stream_t *stream, int32_t timeout_msec); bool mongoc_stream_tls_should_retry (mongoc_stream_t *stream); bool mongoc_stream_tls_should_read (mongoc_stream_t *stream); bool mongoc_stream_tls_should_write (mongoc_stream_t *stream); bool mongoc_stream_tls_check_cert (mongoc_stream_t *stream, const char *host); mongoc_stream_t *mongoc_stream_tls_new (mongoc_stream_t *base_stream, mongoc_ssl_opt_t *opt, int client); BSON_END_DECLS #endif /* MONGOC_STREAM_TLS_H */ libmongoc-1.3.1/src/mongoc/mongoc-stream.c000066400000000000000000000264701264720626300204760ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-array-private.h" #include "mongoc-buffer-private.h" #include "mongoc-error.h" #include "mongoc-errno-private.h" #include "mongoc-flags.h" #include "mongoc-log.h" #include "mongoc-opcode.h" #include "mongoc-rpc-private.h" #include "mongoc-stream.h" #include "mongoc-stream-private.h" #include "mongoc-trace.h" #include "mongoc-util-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream" #ifndef MONGOC_DEFAULT_TIMEOUT_MSEC # define MONGOC_DEFAULT_TIMEOUT_MSEC (60L * 60L * 1000L) #endif /** * mongoc_stream_close: * @stream: A mongoc_stream_t. * * Closes the underlying file-descriptor used by @stream. * * Returns: 0 on success, -1 on failure. */ int mongoc_stream_close (mongoc_stream_t *stream) { int ret; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (stream->close); ret = stream->close(stream); RETURN (ret); } /** * mongoc_stream_failed: * @stream: A mongoc_stream_t. * * Frees any resources referenced by @stream, including the memory allocation * for @stream. * This handler is called upon stream failure, such as network errors, invalid replies * or replicaset reconfigures deleteing the stream */ void mongoc_stream_failed (mongoc_stream_t *stream) { ENTRY; BSON_ASSERT (stream); if (stream->failed) { stream->failed(stream); } else { stream->destroy(stream); } EXIT; } /** * mongoc_stream_destroy: * @stream: A mongoc_stream_t. * * Frees any resources referenced by @stream, including the memory allocation * for @stream. */ void mongoc_stream_destroy (mongoc_stream_t *stream) { ENTRY; BSON_ASSERT (stream); BSON_ASSERT (stream->destroy); stream->destroy(stream); EXIT; } /** * mongoc_stream_flush: * @stream: A mongoc_stream_t. * * Flushes the data in the underlying stream to the transport. * * Returns: 0 on success, -1 on failure. */ int mongoc_stream_flush (mongoc_stream_t *stream) { BSON_ASSERT (stream); return stream->flush(stream); } /** * mongoc_stream_writev: * @stream: A mongoc_stream_t. * @iov: An array of iovec to write to the stream. * @iovcnt: The number of elements in @iov. * * Writes an array of iovec buffers to the underlying stream. * * Returns: the number of bytes written, or -1 upon failure. */ ssize_t mongoc_stream_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { ssize_t ret; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (stream->writev); if (timeout_msec < 0) { timeout_msec = MONGOC_DEFAULT_TIMEOUT_MSEC; } DUMP_IOVEC (writev, iov, iovcnt); ret = stream->writev(stream, iov, iovcnt, timeout_msec); RETURN (ret); } /** * mongoc_stream_write: * @stream: A mongoc_stream_t. * @buf: A buffer to write. * @count: The number of bytes to write into @buf. * * Simplified access to mongoc_stream_writev(). Creates a single iovec * with the buffer provided. * * Returns: -1 on failure, otherwise the number of bytes write. */ ssize_t mongoc_stream_write (mongoc_stream_t *stream, void *buf, size_t count, int32_t timeout_msec) { mongoc_iovec_t iov; ssize_t ret; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (buf); iov.iov_base = buf; iov.iov_len = count; BSON_ASSERT (stream->writev); ret = mongoc_stream_writev (stream, &iov, 1, timeout_msec); RETURN (ret); } /** * mongoc_stream_readv: * @stream: A mongoc_stream_t. * @iov: An array of iovec containing the location and sizes to read. * @iovcnt: the number of elements in @iov. * @min_bytes: the minumum number of bytes to return, or -1. * * Reads into the various buffers pointed to by @iov and associated * buffer lengths. * * If @min_bytes is specified, then at least min_bytes will be returned unless * eof is encountered. This may result in ETIMEDOUT * * Returns: the number of bytes read or -1 on failure. */ ssize_t mongoc_stream_readv (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { ssize_t ret; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (stream->readv); ret = stream->readv (stream, iov, iovcnt, min_bytes, timeout_msec); if (ret >= 0) { DUMP_IOVEC (readv, iov, iovcnt); } RETURN (ret); } /** * mongoc_stream_read: * @stream: A mongoc_stream_t. * @buf: A buffer to write into. * @count: The number of bytes to write into @buf. * @min_bytes: The minimum number of bytes to receive * * Simplified access to mongoc_stream_readv(). Creates a single iovec * with the buffer provided. * * If @min_bytes is specified, then at least min_bytes will be returned unless * eof is encountered. This may result in ETIMEDOUT * * Returns: -1 on failure, otherwise the number of bytes read. */ ssize_t mongoc_stream_read (mongoc_stream_t *stream, void *buf, size_t count, size_t min_bytes, int32_t timeout_msec) { mongoc_iovec_t iov; ssize_t ret; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (buf); iov.iov_base = buf; iov.iov_len = count; BSON_ASSERT (stream->readv); ret = mongoc_stream_readv (stream, &iov, 1, min_bytes, timeout_msec); RETURN (ret); } int mongoc_stream_setsockopt (mongoc_stream_t *stream, int level, int optname, void *optval, socklen_t optlen) { BSON_ASSERT (stream); if (stream->setsockopt) { return stream->setsockopt(stream, level, optname, optval, optlen); } return 0; } mongoc_stream_t * mongoc_stream_get_base_stream (mongoc_stream_t *stream) /* IN */ { BSON_ASSERT (stream); if (stream->get_base_stream) { return stream->get_base_stream (stream); } return stream; } static mongoc_stream_t * mongoc_stream_get_root_stream (mongoc_stream_t *stream) { BSON_ASSERT (stream); while (stream->get_base_stream) { stream = stream->get_base_stream (stream); } return stream; } ssize_t mongoc_stream_poll (mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeout) { mongoc_stream_poll_t *poller = (mongoc_stream_poll_t *)bson_malloc(sizeof(*poller) * nstreams); int i; int last_type = 0; ssize_t rval = -1; errno = 0; for (i = 0; i < nstreams; i++) { poller[i].stream = mongoc_stream_get_root_stream(streams[i].stream); poller[i].events = streams[i].events; poller[i].revents = 0; if (i == 0) { last_type = poller[i].stream->type; } else if (last_type != poller[i].stream->type) { errno = EINVAL; goto CLEANUP; } } if (! poller[0].stream->poll) { errno = EINVAL; goto CLEANUP; } rval = poller[0].stream->poll(poller, nstreams, timeout); if (rval > 0) { for (i = 0; i < nstreams; i++) { streams[i].revents = poller[i].revents; } } CLEANUP: bson_free(poller); return rval; } /* *-------------------------------------------------------------------------- * * mongoc_stream_wait -- * * Internal helper, poll a single stream until it connects. * * For now, only the POLLOUT (connected) event is supported. * * @expire_at should be an absolute time at which to expire using * the monotonic clock (bson_get_monotonic_time(), which is in * microseconds). expire_at of 0 or -1 is prohibited. * * Returns: * true if an event matched. otherwise false. * a timeout will return false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool mongoc_stream_wait (mongoc_stream_t *stream, int64_t expire_at) { mongoc_stream_poll_t poller; int64_t now; int32_t timeout_msec; ssize_t ret; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (expire_at > 0); poller.stream = stream; poller.events = POLLOUT; poller.revents = 0; now = bson_get_monotonic_time(); for (;;) { /* TODO CDRIVER-804 use int64_t for timeouts consistently */ timeout_msec = (int32_t) BSON_MIN ((expire_at - now) / 1000L, INT32_MAX); if (timeout_msec < 0) { timeout_msec = 0; } ret = mongoc_stream_poll (&poller, 1, timeout_msec); if (ret > 0) { /* an event happened, return true if POLLOUT else false */ RETURN (0 != (poller.revents & POLLOUT)); } else if (ret < 0) { /* poll itself failed */ TRACE("errno is: %d", errno); if (MONGOC_ERRNO_IS_AGAIN(errno)) { now = bson_get_monotonic_time(); if (expire_at < now) { RETURN (false); } else { continue; } } else { /* poll failed for some non-transient reason */ RETURN (false); } } else { /* poll timed out */ RETURN (false); } } return true; } bool mongoc_stream_check_closed (mongoc_stream_t *stream) { int ret; ENTRY; if (!stream) { return true; } ret = stream->check_closed(stream); RETURN (ret); } bool _mongoc_stream_writev_full (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec, bson_error_t *error) { size_t total_bytes = 0; int i; ssize_t r; ENTRY; for (i = 0; i < iovcnt; i++) { total_bytes += iov[i].iov_len; } r = mongoc_stream_writev(stream, iov, iovcnt, timeout_msec); TRACE("writev returned: %ld", r); if (r < 0) { if (error) { char buf[128]; char *errstr; errstr = bson_strerror_r(errno, buf, sizeof(buf)); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failure during socket delivery: %s (%d)", errstr, errno); } RETURN(false); } if (r != total_bytes) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failure to send all requested bytes (only sent: %" PRIu64 "/%" PRId64 " in %dms) during socket delivery", (uint64_t) r, (int64_t)total_bytes, timeout_msec); RETURN(false); } RETURN(true); } libmongoc-1.3.1/src/mongoc/mongoc-stream.h000066400000000000000000000122351264720626300204750ustar00rootroot00000000000000/* * Copyright 2013-2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_STREAM_H #define MONGOC_STREAM_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include "mongoc-iovec.h" #include "mongoc-socket.h" BSON_BEGIN_DECLS typedef struct _mongoc_stream_t mongoc_stream_t; typedef struct _mongoc_stream_poll_t { mongoc_stream_t *stream; int events; int revents; } mongoc_stream_poll_t; struct _mongoc_stream_t { int type; void (*destroy) (mongoc_stream_t *stream); int (*close) (mongoc_stream_t *stream); int (*flush) (mongoc_stream_t *stream); ssize_t (*writev) (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec); ssize_t (*readv) (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec); int (*setsockopt) (mongoc_stream_t *stream, int level, int optname, void *optval, socklen_t optlen); mongoc_stream_t *(*get_base_stream) (mongoc_stream_t *stream); bool (*check_closed) (mongoc_stream_t *stream); ssize_t (*poll) (mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeout); void (*failed) (mongoc_stream_t *stream); void *padding [5]; }; mongoc_stream_t *mongoc_stream_get_base_stream (mongoc_stream_t *stream); int mongoc_stream_close (mongoc_stream_t *stream); void mongoc_stream_destroy (mongoc_stream_t *stream); void mongoc_stream_failed (mongoc_stream_t *stream); int mongoc_stream_flush (mongoc_stream_t *stream); ssize_t mongoc_stream_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec); ssize_t mongoc_stream_write (mongoc_stream_t *stream, void *buf, size_t count, int32_t timeout_msec); ssize_t mongoc_stream_readv (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec); ssize_t mongoc_stream_read (mongoc_stream_t *stream, void *buf, size_t count, size_t min_bytes, int32_t timeout_msec); int mongoc_stream_setsockopt (mongoc_stream_t *stream, int level, int optname, void *optval, socklen_t optlen); bool mongoc_stream_check_closed (mongoc_stream_t *stream); ssize_t mongoc_stream_poll (mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeout); BSON_END_DECLS #endif /* MONGOC_STREAM_H */ libmongoc-1.3.1/src/mongoc/mongoc-thread-private.h000066400000000000000000000110111264720626300221100ustar00rootroot00000000000000/* * Copyright 2013 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_THREAD_PRIVATE_H #define MONGOC_THREAD_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-config.h" #if !defined(_WIN32) # include # define MONGOC_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER # define mongoc_cond_t pthread_cond_t # define mongoc_cond_broadcast pthread_cond_broadcast # define mongoc_cond_init(_n) pthread_cond_init((_n), NULL) # define mongoc_cond_wait pthread_cond_wait # define mongoc_cond_signal pthread_cond_signal static BSON_INLINE int mongoc_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, int64_t timeout_msec) { struct timespec to; struct timeval tv; int64_t msec; bson_gettimeofday (&tv); msec = ((int64_t)tv.tv_sec * 1000) + (tv.tv_usec / 1000) + timeout_msec; to.tv_sec = msec / 1000; to.tv_nsec = (msec % 1000) * 1000 * 1000; return pthread_cond_timedwait (cond, mutex, &to); } # define mongoc_cond_destroy pthread_cond_destroy # define mongoc_mutex_t pthread_mutex_t # define mongoc_mutex_init(_n) pthread_mutex_init((_n), NULL) # define mongoc_mutex_lock pthread_mutex_lock # define mongoc_mutex_unlock pthread_mutex_unlock # define mongoc_mutex_destroy pthread_mutex_destroy # define mongoc_thread_t pthread_t # define mongoc_thread_create(_t,_f,_d) pthread_create((_t), NULL, (_f), (_d)) # define mongoc_thread_join(_n) pthread_join((_n), NULL) # define mongoc_once_t pthread_once_t # define mongoc_once pthread_once # define MONGOC_ONCE_FUN(n) void n(void) # define MONGOC_ONCE_RETURN return # ifdef _PTHREAD_ONCE_INIT_NEEDS_BRACES # define MONGOC_ONCE_INIT {PTHREAD_ONCE_INIT} # else # define MONGOC_ONCE_INIT PTHREAD_ONCE_INIT # endif #else # define mongoc_thread_t HANDLE static BSON_INLINE int mongoc_thread_create (mongoc_thread_t *thread, void *(*cb)(void *), void *arg) { *thread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) cb, arg, 0, NULL); return 0; } # define mongoc_thread_join(_n) WaitForSingleObject((_n), INFINITE) # define mongoc_mutex_t CRITICAL_SECTION # define mongoc_mutex_init InitializeCriticalSection # define mongoc_mutex_lock EnterCriticalSection # define mongoc_mutex_unlock LeaveCriticalSection # define mongoc_mutex_destroy DeleteCriticalSection # define mongoc_cond_t CONDITION_VARIABLE # define mongoc_cond_init InitializeConditionVariable # define mongoc_cond_wait(_c, _m) mongoc_cond_timedwait((_c), (_m), INFINITE) static BSON_INLINE int mongoc_cond_timedwait (mongoc_cond_t *cond, mongoc_mutex_t *mutex, int64_t timeout_msec) { int r; if (SleepConditionVariableCS(cond, mutex, timeout_msec)) { return 0; } else { r = GetLastError(); if (r == WAIT_TIMEOUT || r == ERROR_TIMEOUT) { return WSAETIMEDOUT; } else { return EINVAL; } } } # define mongoc_cond_signal WakeConditionVariable # define mongoc_cond_broadcast WakeAllConditionVariable static BSON_INLINE int mongoc_cond_destroy (mongoc_cond_t *_ignored) { return 0; } # define mongoc_once_t INIT_ONCE # define MONGOC_ONCE_INIT INIT_ONCE_STATIC_INIT # define mongoc_once(o, c) InitOnceExecuteOnce(o, c, NULL, NULL) # define MONGOC_ONCE_FUN(n) BOOL CALLBACK n(PINIT_ONCE _ignored_a, PVOID _ignored_b, PVOID *_ignored_c) # define MONGOC_ONCE_RETURN return true #endif #endif /* MONGOC_THREAD_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-topology-description-private.h000066400000000000000000000070771264720626300250570ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_TOPOLOGY_DESCRIPTION_PRIVATE_H #define MONGOC_TOPOLOGY_DESCRIPTION_PRIVATE_H #include "mongoc-set-private.h" #include "mongoc-server-description.h" #define MONGOC_SS_DEFAULT_TIMEOUT_MS 30000 #define MONGOC_SS_DEFAULT_LOCAL_THRESHOLD_MS 15 typedef enum { MONGOC_TOPOLOGY_UNKNOWN, MONGOC_TOPOLOGY_SHARDED, MONGOC_TOPOLOGY_RS_NO_PRIMARY, MONGOC_TOPOLOGY_RS_WITH_PRIMARY, MONGOC_TOPOLOGY_SINGLE, MONGOC_TOPOLOGY_DESCRIPTION_TYPES } mongoc_topology_description_type_t; typedef struct _mongoc_topology_description_t { mongoc_topology_description_type_t type; mongoc_set_t *servers; char *set_name; int64_t max_set_version; bson_oid_t max_election_id; bool compatible; char *compatibility_error; uint32_t max_server_id; bool stale; } mongoc_topology_description_t; typedef enum { MONGOC_SS_READ, MONGOC_SS_WRITE } mongoc_ss_optype_t; void mongoc_topology_description_init (mongoc_topology_description_t *description, mongoc_topology_description_type_t type); void mongoc_topology_description_destroy (mongoc_topology_description_t *description); void mongoc_topology_description_handle_ismaster ( mongoc_topology_description_t *topology, mongoc_server_description_t *sd, const bson_t *reply, int64_t rtt_msec, bson_error_t *error); mongoc_server_description_t * mongoc_topology_description_select (mongoc_topology_description_t *description, mongoc_ss_optype_t optype, const mongoc_read_prefs_t *read_pref, int64_t local_threshold_ms); mongoc_server_description_t * mongoc_topology_description_server_by_id (mongoc_topology_description_t *description, uint32_t id, bson_error_t *error); void mongoc_topology_description_suitable_servers ( mongoc_array_t *set, /* OUT */ mongoc_ss_optype_t optype, mongoc_topology_description_t *topology, const mongoc_read_prefs_t *read_pref, size_t local_threshold_ms); void mongoc_topology_description_invalidate_server (mongoc_topology_description_t *topology, uint32_t id); bool mongoc_topology_description_add_server (mongoc_topology_description_t *topology, const char *server, uint32_t *id /* OUT */); #endif /* MONGOC_TOPOLOGY_DESCRIPTION_H */ libmongoc-1.3.1/src/mongoc/mongoc-topology-description.c000066400000000000000000001305101264720626300233670ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-array-private.h" #include "mongoc-error.h" #include "mongoc-server-description-private.h" #include "mongoc-topology-description-private.h" #include "mongoc-trace.h" #include "mongoc-util-private.h" static void _mongoc_topology_server_dtor (void *server_, void *ctx_) { mongoc_server_description_destroy ((mongoc_server_description_t *)server_); } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_init -- * * Initialize the given topology description * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_topology_description_init (mongoc_topology_description_t *description, mongoc_topology_description_type_t type) { ENTRY; BSON_ASSERT (description); BSON_ASSERT (type == MONGOC_TOPOLOGY_UNKNOWN || type == MONGOC_TOPOLOGY_SINGLE || type == MONGOC_TOPOLOGY_RS_NO_PRIMARY); memset (description, 0, sizeof (*description)); description->type = type; description->servers = mongoc_set_new(8, _mongoc_topology_server_dtor, NULL); description->set_name = NULL; description->max_set_version = MONGOC_NO_SET_VERSION; description->compatible = true; description->compatibility_error = NULL; description->stale = true; EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_destroy -- * * Destroy allocated resources within @description * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_topology_description_destroy (mongoc_topology_description_t *description) { ENTRY; BSON_ASSERT(description); mongoc_set_destroy(description->servers); if (description->set_name) { bson_free (description->set_name); } if (description->compatibility_error) { bson_free (description->compatibility_error); } EXIT; } /* find the primary, then stop iterating */ static bool _mongoc_topology_description_has_primary_cb (void *item, void *ctx /* OUT */) { mongoc_server_description_t *server = (mongoc_server_description_t *)item; mongoc_server_description_t **primary = (mongoc_server_description_t **)ctx; /* TODO should this include MONGOS? */ if (server->type == MONGOC_SERVER_RS_PRIMARY || server->type == MONGOC_SERVER_STANDALONE) { *primary = (mongoc_server_description_t *)item; return false; } return true; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_has_primary -- * * If topology has a primary, return it. * * Returns: * A pointer to the primary, or NULL. * * Side effects: * None * *-------------------------------------------------------------------------- */ static mongoc_server_description_t * _mongoc_topology_description_has_primary (mongoc_topology_description_t *description) { mongoc_server_description_t *primary = NULL; mongoc_set_for_each(description->servers, _mongoc_topology_description_has_primary_cb, &primary); return primary; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_later_election -- * * Check if we've seen a more recent election in the replica set * than this server has. * * Returns: * True if the topology description's max replica set version plus * election id is later than the server description's. * * Side effects: * None * *-------------------------------------------------------------------------- */ static bool _mongoc_topology_description_later_election (mongoc_topology_description_t *td, mongoc_server_description_t *sd) { /* initially max_set_version is -1 and max_election_id is zeroed */ return td->max_set_version > sd->set_version || (td->max_set_version == sd->set_version && bson_oid_compare (&td->max_election_id, &sd->election_id) > 0); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_set_max_set_version -- * * Remember that we've seen a new replica set version. Unconditionally * sets td->set_version to sd->set_version. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_set_max_set_version ( mongoc_topology_description_t *td, mongoc_server_description_t *sd) { td->max_set_version = sd->set_version; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_set_max_election_id -- * * Remember that we've seen a new election id. Unconditionally sets * td->max_election_id to sd->election_id. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_set_max_election_id ( mongoc_topology_description_t *td, mongoc_server_description_t *sd) { bson_oid_copy (&sd->election_id, &td->max_election_id); } static bool _mongoc_topology_description_server_is_candidate ( mongoc_server_description_type_t desc_type, mongoc_read_mode_t read_mode, mongoc_topology_description_type_t topology_type) { switch ((int)topology_type) { case MONGOC_TOPOLOGY_SINGLE: switch ((int)desc_type) { case MONGOC_SERVER_STANDALONE: return true; default: return false; } case MONGOC_TOPOLOGY_RS_NO_PRIMARY: case MONGOC_TOPOLOGY_RS_WITH_PRIMARY: switch ((int)read_mode) { case MONGOC_READ_PRIMARY: switch ((int)desc_type) { case MONGOC_SERVER_POSSIBLE_PRIMARY: case MONGOC_SERVER_RS_PRIMARY: return true; default: return false; } case MONGOC_READ_SECONDARY: switch ((int)desc_type) { case MONGOC_SERVER_RS_SECONDARY: return true; default: return false; } default: switch ((int)desc_type) { case MONGOC_SERVER_POSSIBLE_PRIMARY: case MONGOC_SERVER_RS_PRIMARY: case MONGOC_SERVER_RS_SECONDARY: return true; default: return false; } } case MONGOC_TOPOLOGY_SHARDED: switch ((int)desc_type) { case MONGOC_SERVER_MONGOS: return true; default: return false; } default: return false; } } typedef struct _mongoc_suitable_data_t { mongoc_read_mode_t read_mode; mongoc_topology_description_type_t topology_type; mongoc_server_description_t *primary; /* OUT */ mongoc_server_description_t **candidates; /* OUT */ size_t candidates_len; /* OUT */ bool has_secondary; /* OUT */ } mongoc_suitable_data_t; static bool _mongoc_replica_set_read_suitable_cb (void *item, void *ctx) { mongoc_server_description_t *server = (mongoc_server_description_t *)item; mongoc_suitable_data_t *data = (mongoc_suitable_data_t *)ctx; if (_mongoc_topology_description_server_is_candidate (server->type, data->read_mode, data->topology_type)) { if (server->type == MONGOC_SERVER_RS_PRIMARY) { data->primary = server; if (data->read_mode == MONGOC_READ_PRIMARY || data->read_mode == MONGOC_READ_PRIMARY_PREFERRED) { /* we want a primary and we have one, done! */ return false; } } if (server->type == MONGOC_SERVER_RS_SECONDARY) { data->has_secondary = true; } /* add to our candidates */ data->candidates[data->candidates_len++] = server; } return true; } /* if any mongos are candidates, add them to the candidates array */ static bool _mongoc_find_suitable_mongos_cb (void *item, void *ctx) { mongoc_server_description_t *server = (mongoc_server_description_t *)item; mongoc_suitable_data_t *data = (mongoc_suitable_data_t *)ctx; if (_mongoc_topology_description_server_is_candidate (server->type, data->read_mode, data->topology_type)) { data->candidates[data->candidates_len++] = server; } return true; } /* *------------------------------------------------------------------------- * * mongoc_topology_description_suitable_servers -- * * Return an array of suitable server descriptions for this * operation and read preference. * * NOTE: this method should only be called while holding the mutex on * the owning topology object. * * Returns: * Array of server descriptions, or NULL upon failure. * * Side effects: * None. * *------------------------------------------------------------------------- */ void mongoc_topology_description_suitable_servers ( mongoc_array_t *set, /* OUT */ mongoc_ss_optype_t optype, mongoc_topology_description_t *topology, const mongoc_read_prefs_t *read_pref, size_t local_threshold_ms) { mongoc_suitable_data_t data; mongoc_server_description_t **candidates; mongoc_server_description_t *server; int64_t nearest = -1; int i; mongoc_read_mode_t read_mode = mongoc_read_prefs_get_mode(read_pref); candidates = (mongoc_server_description_t **)bson_malloc0(sizeof(*candidates) * topology->servers->items_len); data.read_mode = read_mode; data.topology_type = topology->type; data.primary = NULL; data.candidates = candidates; data.candidates_len = 0; data.has_secondary = false; /* Single server -- * Either it is suitable or it isn't */ if (topology->type == MONGOC_TOPOLOGY_SINGLE) { server = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, 0); if (_mongoc_topology_description_server_is_candidate (server->type, read_mode, topology->type)) { _mongoc_array_append_val (set, server); } goto DONE; } /* Replica sets -- * Find suitable servers based on read mode */ if (topology->type == MONGOC_TOPOLOGY_RS_NO_PRIMARY || topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) { if (optype == MONGOC_SS_READ) { mongoc_set_for_each(topology->servers, _mongoc_replica_set_read_suitable_cb, &data); /* if we have a primary, it's a candidate, for some read modes we are done */ if (read_mode == MONGOC_READ_PRIMARY || read_mode == MONGOC_READ_PRIMARY_PREFERRED) { if (data.primary) { _mongoc_array_append_val (set, data.primary); goto DONE; } } if (! mongoc_server_description_filter_eligible (data.candidates, data.candidates_len, read_pref)) { if (read_mode == MONGOC_READ_NEAREST) { goto DONE; } else { data.has_secondary = false; } } if (data.has_secondary && (read_mode == MONGOC_READ_SECONDARY || read_mode == MONGOC_READ_SECONDARY_PREFERRED)) { /* secondary or secondary preferred and we have one. */ for (i = 0; i < data.candidates_len; i++) { if (candidates[i] && candidates[i]->type == MONGOC_SERVER_RS_PRIMARY) { candidates[i] = NULL; } } } else if (read_mode == MONGOC_READ_SECONDARY_PREFERRED && data.primary) { /* secondary preferred, but only the one primary is a candidate */ _mongoc_array_append_val (set, data.primary); goto DONE; } } else if (topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) { /* includes optype == MONGOC_SS_WRITE as the exclusion of the above if */ mongoc_set_for_each(topology->servers, _mongoc_topology_description_has_primary_cb, &data.primary); if (data.primary) { _mongoc_array_append_val (set, data.primary); goto DONE; } } } /* Sharded clusters -- * All candidates in the latency window are suitable */ if (topology->type == MONGOC_TOPOLOGY_SHARDED) { mongoc_set_for_each (topology->servers, _mongoc_find_suitable_mongos_cb, &data); } /* Ways to get here: * - secondary read * - secondary preferred read * - primary_preferred and no primary read * - sharded anything * Find the nearest, then select within the window */ for (i = 0; i < data.candidates_len; i++) { if (candidates[i] && (nearest == -1 || nearest > candidates[i]->round_trip_time)) { nearest = candidates[i]->round_trip_time; } } for (i = 0; i < data.candidates_len; i++) { if (candidates[i] && (candidates[i]->round_trip_time <= nearest + local_threshold_ms)) { _mongoc_array_append_val (set, candidates[i]); } } DONE: bson_free (candidates); return; } /* *------------------------------------------------------------------------- * * mongoc_topology_description_select -- * * Return a server description of a node that is appropriate for * the given read preference and operation type. * * NOTE: this method simply attempts to select a server from the * current topology, it does not retry or trigger topology checks. * * NOTE: this method should only be called while holding the mutex on * the owning topology object. * * Returns: * Selected server description, or NULL upon failure. * * Side effects: * None. * *------------------------------------------------------------------------- */ mongoc_server_description_t * mongoc_topology_description_select (mongoc_topology_description_t *topology, mongoc_ss_optype_t optype, const mongoc_read_prefs_t *read_pref, int64_t local_threshold_ms) { mongoc_array_t suitable_servers; mongoc_server_description_t *sd = NULL; ENTRY; if (!topology->compatible) { /* TODO, should we return an error object here, or just treat as a case where there are no suitable servers? */ RETURN(NULL); } if (topology->type == MONGOC_TOPOLOGY_SINGLE) { sd = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, 0); if (sd->has_is_master) { RETURN(sd); } else { RETURN(NULL); } } _mongoc_array_init(&suitable_servers, sizeof(mongoc_server_description_t *)); mongoc_topology_description_suitable_servers(&suitable_servers, optype, topology, read_pref, local_threshold_ms); if (suitable_servers.len != 0) { sd = _mongoc_array_index(&suitable_servers, mongoc_server_description_t*, rand() % suitable_servers.len); } _mongoc_array_destroy (&suitable_servers); RETURN(sd); } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_server_by_id -- * * Get the server description for @id, if that server is present * in @description. Otherwise, return NULL and fill out optional * @error. * * NOTE: In most cases, caller should create a duplicate of the * returned server description. Caller should hold the mutex on the * owning topology object while calling this method and while using * the returned reference. * * Returns: * A mongoc_server_description_t *, or NULL. * * Side effects: * Fills out optional @error if server not found. * *-------------------------------------------------------------------------- */ mongoc_server_description_t * mongoc_topology_description_server_by_id (mongoc_topology_description_t *description, uint32_t id, bson_error_t *error) { mongoc_server_description_t *sd; BSON_ASSERT (description); sd = (mongoc_server_description_t *)mongoc_set_get(description->servers, id); if (!sd) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, "Could not find description for node %u", id); } return sd; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_remove_server -- * * If present, remove this server from this topology description. * * Returns: * None. * * Side effects: * Removes the server description from topology and destroys it. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_remove_server (mongoc_topology_description_t *description, mongoc_server_description_t *server) { BSON_ASSERT (description); BSON_ASSERT (server); mongoc_set_rm(description->servers, server->id); } typedef struct _mongoc_address_and_id_t { const char *address; /* IN */ bool found; /* OUT */ uint32_t id; /* OUT */ } mongoc_address_and_id_t; /* find the given server and stop iterating */ static bool _mongoc_topology_description_has_server_cb (void *item, void *ctx /* IN - OUT */) { mongoc_server_description_t *server = (mongoc_server_description_t *)item; mongoc_address_and_id_t *data = (mongoc_address_and_id_t *)ctx; if (strcasecmp (data->address, server->connection_address) == 0) { data->found = true; data->id = server->id; return false; } return true; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_has_set_version -- * * Whether @topology's max replica set version has been set. * * Returns: * True if the max setVersion was ever set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_topology_description_has_set_version (mongoc_topology_description_t *td) { return td->max_set_version != MONGOC_NO_SET_VERSION; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_topology_has_server -- * * Return true if @server is in @topology. If so, place its id in * @id if given. * * Returns: * True if server is in topology, false otherwise. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_topology_description_has_server (mongoc_topology_description_t *description, const char *address, uint32_t *id /* OUT */) { mongoc_address_and_id_t data; BSON_ASSERT (description); BSON_ASSERT (address); data.address = address; data.found = false; mongoc_set_for_each (description->servers, _mongoc_topology_description_has_server_cb, &data); if (data.found && id) { *id = data.id; } return data.found; } typedef struct _mongoc_address_and_type_t { const char *address; mongoc_server_description_type_t type; } mongoc_address_and_type_t; static bool _mongoc_label_unknown_member_cb (void *item, void *ctx) { mongoc_server_description_t *server = (mongoc_server_description_t *)item; mongoc_address_and_type_t *data = (mongoc_address_and_type_t *)ctx; if (strcasecmp (server->connection_address, data->address) == 0 && server->type == MONGOC_SERVER_UNKNOWN) { mongoc_server_description_set_state(server, data->type); return false; } return true; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_label_unknown_member -- * * Find the server description with the given @address and if its * type is UNKNOWN, set its type to @type. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_label_unknown_member (mongoc_topology_description_t *description, const char *address, mongoc_server_description_type_t type) { mongoc_address_and_type_t data; BSON_ASSERT (description); BSON_ASSERT (address); data.type = type; data.address = address; mongoc_set_for_each(description->servers, _mongoc_label_unknown_member_cb, &data); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_set_state -- * * Change the state of this cluster and unblock things waiting * on a change of topology type. * * Returns: * None. * * Side effects: * Unblocks anything waiting on this description to change states. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_set_state (mongoc_topology_description_t *description, mongoc_topology_description_type_t type) { description->type = type; } static void _update_rs_type (mongoc_topology_description_t *topology) { if (_mongoc_topology_description_has_primary(topology)) { _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_RS_WITH_PRIMARY); } else { _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_RS_NO_PRIMARY); } } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_check_if_has_primary -- * * If there is a primary in topology, set topology * type to RS_WITH_PRIMARY, otherwise set it to * RS_NO_PRIMARY. * * Returns: * None. * * Side effects: * Changes the topology type. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_check_if_has_primary (mongoc_topology_description_t *topology, mongoc_server_description_t *server) { _update_rs_type (topology); } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_invalidate_server -- * * Invalidate a server if a network error occurred while using it in * another part of the client. Server description is set to type * UNKNOWN and other parameters are reset to defaults. * * NOTE: this method should only be called while holding the mutex on * the owning topology object. * *-------------------------------------------------------------------------- */ void mongoc_topology_description_invalidate_server (mongoc_topology_description_t *topology, uint32_t id) { mongoc_server_description_t *sd; bson_error_t error; sd = mongoc_topology_description_server_by_id (topology, id, NULL); mongoc_topology_description_handle_ismaster (topology, sd, NULL, 0, &error); return; } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_add_server -- * * Add the specified server to the cluster topology if it is not * already a member. If @id, place its id in @id. * * NOTE: this method should only be called while holding the mutex on * the owning topology object. * * Return: * True if the server was added or already existed in the topology, * false if an error occurred. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool mongoc_topology_description_add_server (mongoc_topology_description_t *topology, const char *server, uint32_t *id /* OUT */) { uint32_t server_id; mongoc_server_description_t *description; BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server(topology, server, &server_id)){ /* TODO this might not be an accurate count in all cases */ server_id = ++topology->max_server_id; description = (mongoc_server_description_t *)bson_malloc0(sizeof *description); mongoc_server_description_init(description, server, server_id); mongoc_set_add(topology->servers, server_id, description); } if (id) { *id = server_id; } return true; } static void _mongoc_topology_description_add_new_servers ( mongoc_topology_description_t *topology, mongoc_server_description_t *server) { bson_iter_t member_iter; const bson_t *rs_members[3]; int i; rs_members[0] = &server->hosts; rs_members[1] = &server->arbiters; rs_members[2] = &server->passives; for (i = 0; i < 3; i++) { bson_iter_init (&member_iter, rs_members[i]); while (bson_iter_next (&member_iter)) { mongoc_topology_description_add_server(topology, bson_iter_utf8(&member_iter, NULL), NULL); } } } typedef struct _mongoc_primary_and_topology_t { mongoc_topology_description_t *topology; mongoc_server_description_t *primary; } mongoc_primary_and_topology_t; /* invalidate old primaries */ static bool _mongoc_topology_description_invalidate_primaries_cb (void *item, void *ctx) { mongoc_server_description_t *server = (mongoc_server_description_t *)item; mongoc_primary_and_topology_t *data = (mongoc_primary_and_topology_t *)ctx; if (server->id != data->primary->id && server->type == MONGOC_SERVER_RS_PRIMARY) { mongoc_server_description_set_state (server, MONGOC_SERVER_UNKNOWN); mongoc_server_description_set_set_version (server, MONGOC_NO_SET_VERSION); mongoc_server_description_set_election_id (server, NULL); } return true; } /* Remove and destroy all replica set members not in primary's hosts lists */ static void _mongoc_topology_description_remove_unreported_servers ( mongoc_topology_description_t *topology, mongoc_server_description_t *primary) { mongoc_array_t to_remove; int i; mongoc_server_description_t *member; const char *address; _mongoc_array_init (&to_remove, sizeof (mongoc_server_description_t *)); /* Accumulate servers to be removed - do this before calling * _mongoc_topology_description_remove_server, which could call * mongoc_server_description_cleanup on the primary itself if it * doesn't report its own connection_address in its hosts list. * See hosts_differ_from_seeds.json */ for (i = 0; i < topology->servers->items_len; i++) { member = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, i); address = member->connection_address; if (!mongoc_server_description_has_rs_member(primary, address)) { _mongoc_array_append_val (&to_remove, member); } } /* now it's safe to call _mongoc_topology_description_remove_server, * even on the primary */ for (i = 0; i < to_remove.len; i++) { member = _mongoc_array_index ( &to_remove, mongoc_server_description_t *, i); _mongoc_topology_description_remove_server (topology, member); } _mongoc_array_destroy (&to_remove); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_matches_me -- * * Server Discovery And Monitoring Spec: "Removal from the topology of * seed list members where the "me" property does not match the address * used to connect prevents clients from being able to select a server, * only to fail to re-select that server once the primary has responded. * * Returns: * True if "me" matches "connection_address". * * Side Effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_topology_description_matches_me (mongoc_server_description_t *server) { BSON_ASSERT (server->connection_address); if (!server->me) { /* "me" is unknown: consider it a match */ return true; } return strcasecmp (server->connection_address, server->me) == 0; } /* *-------------------------------------------------------------------------- * * _mongoc_update_rs_from_primary -- * * First, determine that this is really the primary: * -If this node isn't in the cluster, do nothing. * -If the cluster's set name is null, set it to node's set name. * Otherwise if the cluster's set name is different from node's, * we found a rogue primary, so remove it from the cluster and * check the cluster for a primary, then return. * -If any of the members of cluster reports an address different * from node's, node cannot be the primary. * Now that we know this is the primary: * -If any hosts, passives, or arbiters in node's description aren't * in the cluster, add them as UNKNOWN servers. * -If the cluster has any servers that aren't in node's description, * remove and destroy them. * Finally, check the cluster for the new primary. * * Returns: * None. * * Side effects: * Changes to the cluster, possible removal of cluster nodes. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_update_rs_from_primary (mongoc_topology_description_t *topology, mongoc_server_description_t *server) { mongoc_primary_and_topology_t data; BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server(topology, server->connection_address, NULL)) return; /* If server->set_name was null this function wouldn't be called from * mongoc_server_description_handle_ismaster(). static code analyzers however * don't know that so we check for it explicitly. */ if (server->set_name) { /* 'Server' can only be the primary if it has the right rs name */ if (!topology->set_name) { topology->set_name = bson_strdup (server->set_name); } else if (strcmp(topology->set_name, server->set_name) != 0) { _mongoc_topology_description_remove_server(topology, server); _update_rs_type (topology); return; } } if (mongoc_server_description_has_set_version (server) && mongoc_server_description_has_election_id (server)) { /* Server Discovery And Monitoring Spec: "The client remembers the * greatest electionId reported by a primary, and distrusts primaries * with lesser electionIds. This prevents the client from oscillating * between the old and new primary during a split-brain period." */ if (_mongoc_topology_description_later_election (topology, server)) { /* stale primary */ mongoc_topology_description_invalidate_server (topology, server->id); _update_rs_type (topology); return; } /* server's electionId >= topology's max electionId */ _mongoc_topology_description_set_max_election_id (topology, server); } if (mongoc_server_description_has_set_version (server) && (! _mongoc_topology_description_has_set_version (topology) || server->set_version > topology->max_set_version)) { _mongoc_topology_description_set_max_set_version (topology, server); } /* 'Server' is the primary! Invalidate other primaries if found */ data.primary = server; data.topology = topology; mongoc_set_for_each(topology->servers, _mongoc_topology_description_invalidate_primaries_cb, &data); /* Add to topology description any new servers primary knows about */ _mongoc_topology_description_add_new_servers (topology, server); /* Remove from topology description any servers primary doesn't know about */ _mongoc_topology_description_remove_unreported_servers (topology, server); /* Finally, set topology type */ _update_rs_type (topology); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_update_rs_without_primary -- * * Update cluster's information when there is no primary. * * Returns: * None. * * Side Effects: * Alters cluster state, may remove node from cluster. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_update_rs_without_primary (mongoc_topology_description_t *topology, mongoc_server_description_t *server) { BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server(topology, server->connection_address, NULL)) { return; } /* make sure we're talking about the same replica set */ if (server->set_name) { if (!topology->set_name) { topology->set_name = bson_strdup(server->set_name); } else if (strcmp(topology->set_name, server->set_name)!= 0) { _mongoc_topology_description_remove_server(topology, server); return; } } /* Add new servers that this replica set member knows about */ _mongoc_topology_description_add_new_servers (topology, server); if (!_mongoc_topology_description_matches_me (server)) { _mongoc_topology_description_remove_server(topology, server); return; } /* If this server thinks there is a primary, label it POSSIBLE_PRIMARY */ if (server->current_primary) { _mongoc_topology_description_label_unknown_member(topology, server->current_primary, MONGOC_SERVER_POSSIBLE_PRIMARY); } } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_update_rs_with_primary_from_member -- * * Update cluster's information when there is a primary, but the * update is coming from another replica set member. * * Returns: * None. * * Side Effects: * Alters cluster state. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_update_rs_with_primary_from_member (mongoc_topology_description_t *topology, mongoc_server_description_t *server) { BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server(topology, server->connection_address, NULL)) { return; } /* set_name should never be null here */ if (strcmp(topology->set_name, server->set_name) != 0) { _mongoc_topology_description_remove_server(topology, server); _update_rs_type (topology); return; } if (!_mongoc_topology_description_matches_me (server)) { _mongoc_topology_description_remove_server(topology, server); return; } /* If there is no primary, label server's current_primary as the POSSIBLE_PRIMARY */ if (!_mongoc_topology_description_has_primary(topology) && server->current_primary) { _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_RS_NO_PRIMARY); _mongoc_topology_description_label_unknown_member(topology, server->current_primary, MONGOC_SERVER_POSSIBLE_PRIMARY); } } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_set_topology_type_to_sharded -- * * Sets topology's type to SHARDED. * * Returns: * None * * Side effects: * Alter's topology's type * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_set_topology_type_to_sharded (mongoc_topology_description_t *topology, mongoc_server_description_t *server) { _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_SHARDED); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_transition_unknown_to_rs_no_primary -- * * Encapsulates transition from cluster state UNKNOWN to * RS_NO_PRIMARY. Sets the type to RS_NO_PRIMARY, * then updates the replica set accordingly. * * Returns: * None. * * Side effects: * Changes topology state. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_transition_unknown_to_rs_no_primary (mongoc_topology_description_t *topology, mongoc_server_description_t *server) { _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_RS_NO_PRIMARY); _mongoc_topology_description_update_rs_without_primary(topology, server); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_remove_and_check_primary -- * * Remove the server and check if the topology still has a primary. * * Returns: * None. * * Side effects: * Removes server from topology and destroys it. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_remove_and_check_primary (mongoc_topology_description_t *topology, mongoc_server_description_t *server) { _mongoc_topology_description_remove_server(topology, server); _update_rs_type (topology); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_update_unknown_with_standalone -- * * If the cluster doesn't contain this server, do nothing. * Otherwise, if the topology only has one seed, change its * type to SINGLE. If the topology has multiple seeds, it does not * include us, so remove this server and destroy it. * * Returns: * None. * * Side effects: * Changes the topology type, might remove server from topology. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_update_unknown_with_standalone (mongoc_topology_description_t *topology, mongoc_server_description_t *server) { BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server(topology, server->connection_address, NULL)) return; if (topology->servers->items_len > 1) { /* This cluster contains other servers, it cannot be a standalone. */ _mongoc_topology_description_remove_server(topology, server); } else { _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_SINGLE); } } /* *-------------------------------------------------------------------------- * * This table implements the 'ToplogyType' table outlined in the Server * Discovery and Monitoring spec. Each row represents a server type, * and each column represents the topology type. Given a current topology * type T and a newly-observed server type S, use the function at * state_transions[S][T] to transition to a new state. * * Rows should be read like so: * { server type for this row * UNKNOWN, * SHARDED, * RS_NO_PRIMARY, * RS_WITH_PRIMARY * } * *-------------------------------------------------------------------------- */ typedef void (*transition_t)(mongoc_topology_description_t *topology, mongoc_server_description_t *server); transition_t gSDAMTransitionTable[MONGOC_SERVER_DESCRIPTION_TYPES][MONGOC_TOPOLOGY_DESCRIPTION_TYPES] = { { /* UNKNOWN */ NULL, /* MONGOC_TOPOLOGY_UNKNOWN */ NULL, /* MONGOC_TOPOLOGY_SHARDED */ NULL, /* MONGOC_TOPOLOGY_RS_NO_PRIMARY */ _mongoc_topology_description_check_if_has_primary /* MONGOC_TOPOLOGY_RS_WITH_PRIMARY */ }, { /* STANDALONE */ _mongoc_topology_description_update_unknown_with_standalone, _mongoc_topology_description_remove_server, _mongoc_topology_description_remove_server, _mongoc_topology_description_remove_and_check_primary }, { /* MONGOS */ _mongoc_topology_description_set_topology_type_to_sharded, NULL, _mongoc_topology_description_remove_server, _mongoc_topology_description_remove_and_check_primary }, { /* POSSIBLE_PRIMARY */ NULL, NULL, NULL, NULL }, { /* PRIMARY */ _mongoc_topology_description_update_rs_from_primary, _mongoc_topology_description_remove_server, _mongoc_topology_description_update_rs_from_primary, _mongoc_topology_description_update_rs_from_primary }, { /* SECONDARY */ _mongoc_topology_description_transition_unknown_to_rs_no_primary, _mongoc_topology_description_remove_server, _mongoc_topology_description_update_rs_without_primary, _mongoc_topology_description_update_rs_with_primary_from_member }, { /* ARBITER */ _mongoc_topology_description_transition_unknown_to_rs_no_primary, _mongoc_topology_description_remove_server, _mongoc_topology_description_update_rs_without_primary, _mongoc_topology_description_update_rs_with_primary_from_member }, { /* RS_OTHER */ _mongoc_topology_description_transition_unknown_to_rs_no_primary, _mongoc_topology_description_remove_server, _mongoc_topology_description_update_rs_without_primary, _mongoc_topology_description_update_rs_with_primary_from_member }, { /* RS_GHOST */ NULL, _mongoc_topology_description_remove_server, NULL, _mongoc_topology_description_check_if_has_primary } }; /* *-------------------------------------------------------------------------- * * mongoc_topology_description_handle_ismaster -- * * Handle an ismaster. This is called by the background SDAM process, * and by client when invalidating servers. * * NOTE: this method should only be called while holding the mutex on * the owning topology object. * *-------------------------------------------------------------------------- */ void mongoc_topology_description_handle_ismaster ( mongoc_topology_description_t *topology, mongoc_server_description_t *sd, const bson_t *ismaster_response, int64_t rtt_msec, bson_error_t *error) { BSON_ASSERT (topology); BSON_ASSERT (sd); if (!_mongoc_topology_description_has_server (topology, sd->connection_address, NULL)) { MONGOC_DEBUG("Couldn't find %s in Topology Description", sd->connection_address); return; } mongoc_server_description_handle_ismaster (sd, ismaster_response, rtt_msec, error); if (gSDAMTransitionTable[sd->type][topology->type]) { TRACE("Transitioning to %d for %d", topology->type, sd->type); gSDAMTransitionTable[sd->type][topology->type] (topology, sd); } else { TRACE("No transition entry to %d for %d", topology->type, sd->type); } } libmongoc-1.3.1/src/mongoc/mongoc-topology-private.h000066400000000000000000000074021264720626300225260ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_TOPOLOGY_PRIVATE_H #define MONGOC_TOPOLOGY_PRIVATE_H #include "mongoc-read-prefs-private.h" #include "mongoc-topology-scanner-private.h" #include "mongoc-server-description-private.h" #include "mongoc-topology-description-private.h" #include "mongoc-thread-private.h" #include "mongoc-uri.h" #define MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS 500 #define MONGOC_TOPOLOGY_SOCKET_CHECK_INTERVAL_MS 5000 #define MONGOC_TOPOLOGY_COOLDOWN_MS 5000 #define MONGOC_TOPOLOGY_SERVER_SELECTION_TIMEOUT_MS 30000 #define MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_MULTI_THREADED 10000 #define MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_SINGLE_THREADED 60000 typedef enum { MONGOC_TOPOLOGY_BG_OFF, MONGOC_TOPOLOGY_BG_RUNNING, MONGOC_TOPOLOGY_BG_SHUTTING_DOWN, } mongoc_topology_bg_state_t; typedef struct _mongoc_topology_t { mongoc_topology_description_t description; mongoc_uri_t *uri; mongoc_topology_scanner_t *scanner; bool server_selection_try_once; int64_t last_scan; int64_t connect_timeout_msec; int64_t server_selection_timeout_msec; int64_t heartbeat_msec; mongoc_mutex_t mutex; mongoc_cond_t cond_client; mongoc_cond_t cond_server; mongoc_thread_t thread; mongoc_topology_bg_state_t bg_thread_state; bool scan_requested; bool scanning; bool got_ismaster; bool shutdown_requested; bool single_threaded; bool stale; } mongoc_topology_t; mongoc_topology_t * mongoc_topology_new (const mongoc_uri_t *uri, bool single_threaded); void mongoc_topology_destroy (mongoc_topology_t *topology); mongoc_server_description_t * mongoc_topology_select (mongoc_topology_t *topology, mongoc_ss_optype_t optype, const mongoc_read_prefs_t *read_prefs, int64_t local_threshold_msec, bson_error_t *error); mongoc_server_description_t * mongoc_topology_server_by_id (mongoc_topology_t *topology, uint32_t id, bson_error_t *error); bool mongoc_topology_get_server_type (mongoc_topology_t *topology, uint32_t id, mongoc_topology_description_type_t *topology_type, mongoc_server_description_type_t *server_type, bson_error_t *error); void mongoc_topology_request_scan (mongoc_topology_t *topology); void mongoc_topology_invalidate_server (mongoc_topology_t *topology, uint32_t id); int64_t mongoc_topology_server_timestamp (mongoc_topology_t *topology, uint32_t id); #endif libmongoc-1.3.1/src/mongoc/mongoc-topology-scanner-private.h000066400000000000000000000123431264720626300241550ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_TOPOLOGY_SCANNER_PRIVATE_H #define MONGOC_TOPOLOGY_SCANNER_PRIVATE_H /* TODO: rename to TOPOLOGY scanner */ #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-async-private.h" #include "mongoc-async-cmd-private.h" #include "mongoc-host-list.h" BSON_BEGIN_DECLS typedef void (*mongoc_topology_scanner_cb_t)(uint32_t id, const bson_t *bson, int64_t rtt, void *data, bson_error_t *error); struct mongoc_topology_scanner; typedef struct mongoc_topology_scanner_node { uint32_t id; mongoc_async_cmd_t *cmd; mongoc_stream_t *stream; int64_t timestamp; int64_t last_used; int64_t last_failed; bool has_auth; mongoc_host_list_t host; struct addrinfo *dns_results; struct addrinfo *current_dns_result; struct mongoc_topology_scanner *ts; struct mongoc_topology_scanner_node *next; struct mongoc_topology_scanner_node *prev; bool retired; bson_error_t last_error; } mongoc_topology_scanner_node_t; typedef struct mongoc_topology_scanner { mongoc_async_t *async; mongoc_topology_scanner_node_t *nodes; uint32_t seq; bson_t ismaster_cmd; mongoc_topology_scanner_cb_t cb; void *cb_data; bool in_progress; const mongoc_uri_t *uri; mongoc_async_cmd_setup_t setup; mongoc_stream_initiator_t initiator; void *initiator_context; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t *ssl_opts; #endif } mongoc_topology_scanner_t; mongoc_topology_scanner_t * mongoc_topology_scanner_new (const mongoc_uri_t *uri, mongoc_topology_scanner_cb_t cb, void *data); void mongoc_topology_scanner_destroy (mongoc_topology_scanner_t *ts); mongoc_topology_scanner_node_t * mongoc_topology_scanner_add (mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, uint32_t id); void mongoc_topology_scanner_add_and_scan (mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, uint32_t id, int64_t timeout_msec); void mongoc_topology_scanner_node_retire (mongoc_topology_scanner_node_t *node); void mongoc_topology_scanner_node_disconnect (mongoc_topology_scanner_node_t *node, bool failed); void mongoc_topology_scanner_node_destroy (mongoc_topology_scanner_node_t *node, bool failed); void mongoc_topology_scanner_start (mongoc_topology_scanner_t *ts, int32_t timeout_msec, bool obey_cooldown); bool mongoc_topology_scanner_work (mongoc_topology_scanner_t *ts, int32_t timeout_msec); void mongoc_topology_scanner_sum_errors (mongoc_topology_scanner_t *ts, bson_error_t *error); void mongoc_topology_scanner_reset (mongoc_topology_scanner_t *ts); bool mongoc_topology_scanner_node_setup (mongoc_topology_scanner_node_t *node, bson_error_t *error); mongoc_topology_scanner_node_t * mongoc_topology_scanner_get_node (mongoc_topology_scanner_t *ts, uint32_t id); bool mongoc_topology_scanner_has_node_for_host (mongoc_topology_scanner_t *ts, mongoc_host_list_t *host); void mongoc_topology_scanner_set_stream_initiator (mongoc_topology_scanner_t *ts, mongoc_stream_initiator_t si, void *ctx); #ifdef MONGOC_ENABLE_SSL void mongoc_topology_scanner_set_ssl_opts (mongoc_topology_scanner_t *ts, mongoc_ssl_opt_t *opts); #endif BSON_END_DECLS #endif /* MONGOC_TOPOLOGY_SCANNER_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-topology-scanner.c000066400000000000000000000437601264720626300225070ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-error.h" #include "mongoc-trace.h" #include "mongoc-topology-scanner-private.h" #include "mongoc-stream-socket.h" #ifdef MONGOC_ENABLE_SSL #include "mongoc-stream-tls.h" #endif #include "mongoc-counters-private.h" #include "utlist.h" #include "mongoc-topology-private.h" #include "mongoc-host-list-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "topology_scanner" static void mongoc_topology_scanner_ismaster_handler (mongoc_async_cmd_result_t async_status, const bson_t *ismaster_response, int64_t rtt_msec, void *data, bson_error_t *error); mongoc_topology_scanner_t * mongoc_topology_scanner_new (const mongoc_uri_t *uri, mongoc_topology_scanner_cb_t cb, void *data) { mongoc_topology_scanner_t *ts = (mongoc_topology_scanner_t *)bson_malloc0 (sizeof (*ts)); ts->async = mongoc_async_new (); bson_init (&ts->ismaster_cmd); BSON_APPEND_INT32 (&ts->ismaster_cmd, "isMaster", 1); ts->cb = cb; ts->cb_data = data; ts->uri = uri; return ts; } #ifdef MONGOC_ENABLE_SSL void mongoc_topology_scanner_set_ssl_opts (mongoc_topology_scanner_t *ts, mongoc_ssl_opt_t *opts) { ts->ssl_opts = opts; ts->setup = mongoc_async_cmd_tls_setup; } #endif void mongoc_topology_scanner_set_stream_initiator (mongoc_topology_scanner_t *ts, mongoc_stream_initiator_t si, void *ctx) { ts->initiator = si; ts->initiator_context = ctx; ts->setup = NULL; } void mongoc_topology_scanner_destroy (mongoc_topology_scanner_t *ts) { mongoc_topology_scanner_node_t *ele, *tmp; DL_FOREACH_SAFE (ts->nodes, ele, tmp) { mongoc_topology_scanner_node_destroy (ele, false); } mongoc_async_destroy (ts->async); bson_destroy (&ts->ismaster_cmd); bson_free (ts); } mongoc_topology_scanner_node_t * mongoc_topology_scanner_add (mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, uint32_t id) { mongoc_topology_scanner_node_t *node; node = (mongoc_topology_scanner_node_t *) bson_malloc0 (sizeof (*node)); memcpy (&node->host, host, sizeof (*host)); node->id = id; node->ts = ts; node->last_failed = -1; DL_APPEND(ts->nodes, node); return node; } void mongoc_topology_scanner_add_and_scan (mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, uint32_t id, int64_t timeout_msec) { mongoc_topology_scanner_node_t *node; BSON_ASSERT (timeout_msec < INT32_MAX); node = mongoc_topology_scanner_add (ts, host, id); /* begin non-blocking connection, don't wait for success */ if (node && mongoc_topology_scanner_node_setup (node, &node->last_error)) { node->cmd = mongoc_async_cmd ( ts->async, node->stream, ts->setup, node->host.host, "admin", &ts->ismaster_cmd, &mongoc_topology_scanner_ismaster_handler, node, (int32_t) timeout_msec); } /* if setup fails the node stays in the scanner. destroyed after the scan. */ return; } void mongoc_topology_scanner_node_retire (mongoc_topology_scanner_node_t *node) { if (node->cmd) { node->cmd->state = MONGOC_ASYNC_CMD_CANCELED_STATE; } node->retired = true; } void mongoc_topology_scanner_node_disconnect (mongoc_topology_scanner_node_t *node, bool failed) { if (node->dns_results) { freeaddrinfo (node->dns_results); node->dns_results = NULL; node->current_dns_result = NULL; } if (node->cmd) { mongoc_async_cmd_destroy (node->cmd); node->cmd = NULL; } if (node->stream) { if (failed) { mongoc_stream_failed (node->stream); } else { mongoc_stream_destroy (node->stream); } node->stream = NULL; } } void mongoc_topology_scanner_node_destroy (mongoc_topology_scanner_node_t *node, bool failed) { DL_DELETE (node->ts->nodes, node); mongoc_topology_scanner_node_disconnect (node, failed); bson_free (node); } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_get_node -- * * Return the scanner node with the given id. * * NOTE: only use this method when single-threaded! * *-------------------------------------------------------------------------- */ mongoc_topology_scanner_node_t * mongoc_topology_scanner_get_node (mongoc_topology_scanner_t *ts, uint32_t id) { mongoc_topology_scanner_node_t *ele, *tmp; DL_FOREACH_SAFE (ts->nodes, ele, tmp) { if (ele->id == id) { return ele; } if (ele->id > id) { break; } } return NULL; } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_has_node_for_host -- * * Whether the scanner has a node for the given host and port. * *-------------------------------------------------------------------------- */ bool mongoc_topology_scanner_has_node_for_host (mongoc_topology_scanner_t *ts, mongoc_host_list_t *host) { mongoc_topology_scanner_node_t *ele, *tmp; DL_FOREACH_SAFE (ts->nodes, ele, tmp) { if (_mongoc_host_list_equal (&ele->host, host)) { return true; } } return false; } /* *----------------------------------------------------------------------- * * This is the callback passed to async_cmd when we're running * ismasters from within the topology monitor. * *----------------------------------------------------------------------- */ static void mongoc_topology_scanner_ismaster_handler (mongoc_async_cmd_result_t async_status, const bson_t *ismaster_response, int64_t rtt_msec, void *data, bson_error_t *error) { mongoc_topology_scanner_node_t *node; int64_t now; const char *message; BSON_ASSERT (data); node = (mongoc_topology_scanner_node_t *)data; node->cmd = NULL; if (node->retired) { return; } now = bson_get_monotonic_time (); /* if no ismaster response, async cmd had an error or timed out */ if (!ismaster_response || async_status == MONGOC_ASYNC_CMD_ERROR || async_status == MONGOC_ASYNC_CMD_TIMEOUT) { mongoc_stream_failed (node->stream); node->stream = NULL; node->last_failed = now; message = async_status == MONGOC_ASYNC_CMD_TIMEOUT ? "connection error" : "connection timeout"; bson_set_error (&node->last_error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_STREAM_CONNECT, "%s calling ismaster on \'%s\'", message, node->host.host_and_port); } else { node->last_failed = -1; } node->last_used = now; node->ts->cb (node->id, ismaster_response, rtt_msec, node->ts->cb_data, error); } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_node_connect_tcp -- * * Create a socket stream for this node, begin a non-blocking * connect and return. * * Returns: * A stream. On failure, return NULL and fill out the error. * *-------------------------------------------------------------------------- */ static mongoc_stream_t * mongoc_topology_scanner_node_connect_tcp (mongoc_topology_scanner_node_t *node, bson_error_t *error) { mongoc_socket_t *sock = NULL; struct addrinfo hints; struct addrinfo *rp; char portstr [8]; mongoc_host_list_t *host; int s; ENTRY; host = &node->host; if (!node->dns_results) { bson_snprintf (portstr, sizeof portstr, "%hu", host->port); memset (&hints, 0, sizeof hints); hints.ai_family = host->family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = 0; s = getaddrinfo (host->host, portstr, &hints, &node->dns_results); if (s != 0) { mongoc_counter_dns_failure_inc (); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, "Failed to resolve '%s'", host->host); RETURN (NULL); } node->current_dns_result = node->dns_results; mongoc_counter_dns_success_inc (); } for (; node->current_dns_result; node->current_dns_result = node->current_dns_result->ai_next) { rp = node->current_dns_result; /* * Create a new non-blocking socket. */ if (!(sock = mongoc_socket_new (rp->ai_family, rp->ai_socktype, rp->ai_protocol))) { continue; } mongoc_socket_connect (sock, rp->ai_addr, (socklen_t)rp->ai_addrlen, 0); break; } if (!sock) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "Failed to connect to target host: '%s'", host->host_and_port); freeaddrinfo (node->dns_results); node->dns_results = NULL; node->current_dns_result = NULL; RETURN (NULL); } return mongoc_stream_socket_new (sock); } static mongoc_stream_t * mongoc_topology_scanner_node_connect_unix (mongoc_topology_scanner_node_t *node, bson_error_t *error) { #ifdef _WIN32 ENTRY; bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "UNIX domain sockets not supported on win32."); RETURN (NULL); #else struct sockaddr_un saddr; mongoc_socket_t *sock; mongoc_stream_t *ret = NULL; mongoc_host_list_t *host; ENTRY; host = &node->host; memset (&saddr, 0, sizeof saddr); saddr.sun_family = AF_UNIX; bson_snprintf (saddr.sun_path, sizeof saddr.sun_path - 1, "%s", host->host); sock = mongoc_socket_new (AF_UNIX, SOCK_STREAM, 0); if (sock == NULL) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to create socket."); RETURN (NULL); } if (-1 == mongoc_socket_connect (sock, (struct sockaddr *)&saddr, sizeof saddr, -1)) { char buf[128]; char *errstr; errstr = bson_strerror_r(mongoc_socket_errno(sock), buf, sizeof(buf)); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "Failed to connect to UNIX domain socket: %s", errstr); mongoc_socket_destroy (sock); RETURN (NULL); } ret = mongoc_stream_socket_new (sock); RETURN (ret); #endif } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_node_setup -- * * Create a stream and begin a non-blocking connect. * * Returns: * true on success, or false and error is set. * *-------------------------------------------------------------------------- */ bool mongoc_topology_scanner_node_setup (mongoc_topology_scanner_node_t *node, bson_error_t *error) { mongoc_stream_t *sock_stream; if (node->stream) { return true; } BSON_ASSERT (!node->retired); if (node->ts->initiator) { sock_stream = node->ts->initiator (node->ts->uri, &node->host, node->ts->initiator_context, error); } else { if (node->host.family == AF_UNIX) { sock_stream = mongoc_topology_scanner_node_connect_unix (node, error); } else { sock_stream = mongoc_topology_scanner_node_connect_tcp (node, error); } #ifdef MONGOC_ENABLE_SSL if (sock_stream && node->ts->ssl_opts) { sock_stream = mongoc_stream_tls_new (sock_stream, node->ts->ssl_opts, 1); } #endif } if (!sock_stream) { /* Pass a rtt of -1 if we couldn't initialize a stream in node_setup */ node->ts->cb (node->id, NULL, -1, node->ts->cb_data, error); return false; } node->stream = sock_stream; node->has_auth = false; node->timestamp = bson_get_monotonic_time (); return true; } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_start -- * * Initializes the scanner and begins a full topology check. This * should be called once before calling mongoc_topology_scanner_work() * repeatedly to complete the scan. * * If "obey_cooldown" is true, this is a single-threaded blocking scan * that must obey the Server Discovery And Monitoring Spec's cooldownMS: * * "After a single-threaded client gets a network error trying to check * a server, the client skips re-checking the server until cooldownMS has * passed. * * "This avoids spending connectTimeoutMS on each unavailable server * during each scan. * * "This value MUST be 5000 ms, and it MUST NOT be configurable." * *-------------------------------------------------------------------------- */ void mongoc_topology_scanner_start (mongoc_topology_scanner_t *ts, int32_t timeout_msec, bool obey_cooldown) { mongoc_topology_scanner_node_t *node, *tmp; int64_t cooldown = INT64_MAX; BSON_ASSERT (ts); if (ts->in_progress) { return; } if (obey_cooldown) { /* when current cooldown period began */ cooldown = bson_get_monotonic_time () - 1000 * MONGOC_TOPOLOGY_COOLDOWN_MS; } DL_FOREACH_SAFE (ts->nodes, node, tmp) { /* check node if it last failed before current cooldown period began */ if (node->last_failed < cooldown) { if (mongoc_topology_scanner_node_setup (node, &node->last_error)) { BSON_ASSERT (!node->cmd); node->cmd = mongoc_async_cmd ( ts->async, node->stream, ts->setup, node->host.host, "admin", &ts->ismaster_cmd, &mongoc_topology_scanner_ismaster_handler, node, timeout_msec); } } } } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_work -- * * Crank the knob on the topology scanner state machine. This should * be called only after mongoc_topology_scanner_start() has been used * to begin the scan. * * Returns: * true if there is more work to do, false if scan is done. * *-------------------------------------------------------------------------- */ bool mongoc_topology_scanner_work (mongoc_topology_scanner_t *ts, int32_t timeout_msec) { bool r; r = mongoc_async_run (ts->async, timeout_msec); if (! r) { ts->in_progress = false; } return r; } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_sum_errors -- * * Summarizes all scanner node errors into one error message * *-------------------------------------------------------------------------- */ void mongoc_topology_scanner_sum_errors (mongoc_topology_scanner_t *ts, bson_error_t *error) { mongoc_topology_scanner_node_t *node, *tmp; DL_FOREACH_SAFE (ts->nodes, node, tmp) { if (node->last_error.code) { char *msg = NULL; if (error->code) { msg = bson_strdup(error->message); } bson_set_error(error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "%s[%s] ", msg ? msg : "", node->last_error.message); if (msg) { bson_free (msg); } } } if (error->code) { error->message[strlen(error->message)-1] = '\0'; } } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_reset -- * * Reset "retired" nodes that failed or were removed in the previous * scan. * *-------------------------------------------------------------------------- */ void mongoc_topology_scanner_reset (mongoc_topology_scanner_t *ts) { mongoc_topology_scanner_node_t *node, *tmp; DL_FOREACH_SAFE (ts->nodes, node, tmp) { if (node->retired) { mongoc_topology_scanner_node_destroy (node, true); } } } libmongoc-1.3.1/src/mongoc/mongoc-topology.c000066400000000000000000000712731264720626300210600ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-error.h" #include "mongoc-topology-private.h" #include "mongoc-uri-private.h" #include "mongoc-util-private.h" #include "utlist.h" static void _mongoc_topology_background_thread_stop (mongoc_topology_t *topology); static void _mongoc_topology_background_thread_start (mongoc_topology_t *topology); static void _mongoc_topology_request_scan (mongoc_topology_t *topology); static bool _mongoc_topology_reconcile_add_nodes (void *item, void *ctx) { mongoc_server_description_t *sd = item; mongoc_topology_t *topology = (mongoc_topology_t *)ctx; mongoc_topology_scanner_t *scanner = topology->scanner; /* quickly search by id, then check if a node for this host was retired in * this scan. */ if (! mongoc_topology_scanner_get_node (scanner, sd->id) && ! mongoc_topology_scanner_has_node_for_host (scanner, &sd->host)) { mongoc_topology_scanner_add_and_scan (scanner, &sd->host, sd->id, topology->connect_timeout_msec); } return true; } void mongoc_topology_reconcile (mongoc_topology_t *topology) { mongoc_topology_scanner_node_t *ele, *tmp; mongoc_topology_description_t *description; mongoc_topology_scanner_t *scanner; description = &topology->description; scanner = topology->scanner; /* Add newly discovered nodes */ mongoc_set_for_each(description->servers, _mongoc_topology_reconcile_add_nodes, topology); /* Remove removed nodes */ DL_FOREACH_SAFE (scanner->nodes, ele, tmp) { if (!mongoc_topology_description_server_by_id (description, ele->id, NULL)) { mongoc_topology_scanner_node_retire (ele); } } } /* *------------------------------------------------------------------------- * * _mongoc_topology_scanner_cb -- * * Callback method to handle ismaster responses received by async * command objects. * * NOTE: This method locks the given topology's mutex. * *------------------------------------------------------------------------- */ void _mongoc_topology_scanner_cb (uint32_t id, const bson_t *ismaster_response, int64_t rtt_msec, void *data, bson_error_t *error) { mongoc_topology_t *topology; mongoc_server_description_t *sd; BSON_ASSERT (data); topology = (mongoc_topology_t *)data; if (rtt_msec >= 0) { /* If the scanner failed to create a socket for this server, that means * we're in scanner_start, which means we're under the mutex. So don't * take the mutex for rtt < 0 */ mongoc_mutex_lock (&topology->mutex); } sd = mongoc_topology_description_server_by_id (&topology->description, id, NULL); if (sd) { mongoc_topology_description_handle_ismaster (&topology->description, sd, ismaster_response, rtt_msec, error); /* The processing of the ismaster results above may have added/removed * server descriptions. We need to reconcile that with our monitoring agents */ mongoc_topology_reconcile(topology); /* TODO only wake up all clients if we found any topology changes */ mongoc_cond_broadcast (&topology->cond_client); } if (rtt_msec >= 0) { mongoc_mutex_unlock (&topology->mutex); } } /* *------------------------------------------------------------------------- * * mongoc_topology_new -- * * Creates and returns a new topology object. * * Returns: * A new topology object. * * Side effects: * None. * *------------------------------------------------------------------------- */ mongoc_topology_t * mongoc_topology_new (const mongoc_uri_t *uri, bool single_threaded) { mongoc_topology_t *topology; mongoc_topology_description_type_t init_type; uint32_t id; const mongoc_host_list_t *hl; BSON_ASSERT (uri); topology = (mongoc_topology_t *)bson_malloc0(sizeof *topology); /* * Not ideal, but there's no great way to do this. * Base on the URI, we assume: * - if we've got a replicaSet name, initialize to RS_NO_PRIMARY * - otherwise, if the seed list has a single host, initialize to SINGLE * - everything else gets initialized to UNKNOWN */ if (mongoc_uri_get_replica_set(uri)) { init_type = MONGOC_TOPOLOGY_RS_NO_PRIMARY; } else { hl = mongoc_uri_get_hosts(uri); if (hl->next) { init_type = MONGOC_TOPOLOGY_UNKNOWN; } else { init_type = MONGOC_TOPOLOGY_SINGLE; } } mongoc_topology_description_init(&topology->description, init_type); topology->description.set_name = bson_strdup(mongoc_uri_get_replica_set(uri)); topology->uri = mongoc_uri_copy (uri); topology->scanner = mongoc_topology_scanner_new (topology->uri, _mongoc_topology_scanner_cb, topology); topology->single_threaded = single_threaded; if (single_threaded) { /* Server Selection Spec: * * "Single-threaded drivers MUST provide a "serverSelectionTryOnce" * mode, in which the driver scans the topology exactly once after * server selection fails, then either selects a server or raises an * error. * * "The serverSelectionTryOnce option MUST be true by default." */ topology->server_selection_try_once = mongoc_uri_get_option_as_bool ( uri, "serverselectiontryonce", true); } else { topology->server_selection_try_once = false; } topology->server_selection_timeout_msec = mongoc_uri_get_option_as_int32( topology->uri, "serverselectiontimeoutms", MONGOC_TOPOLOGY_SERVER_SELECTION_TIMEOUT_MS); /* Total time allowed to check a server is connectTimeoutMS. * Server Discovery And Monitoring Spec: * * "The socket used to check a server MUST use the same connectTimeoutMS as * regular sockets. Multi-threaded clients SHOULD set monitoring sockets' * socketTimeoutMS to the connectTimeoutMS." */ topology->connect_timeout_msec = mongoc_uri_get_option_as_int32( topology->uri, "connecttimeoutms", MONGOC_DEFAULT_CONNECTTIMEOUTMS); topology->heartbeat_msec = mongoc_uri_get_option_as_int32( topology->uri, "heartbeatfrequencyms", (single_threaded ? MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_SINGLE_THREADED : MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_MULTI_THREADED) ); mongoc_mutex_init (&topology->mutex); mongoc_cond_init (&topology->cond_client); mongoc_cond_init (&topology->cond_server); for ( hl = mongoc_uri_get_hosts (uri); hl; hl = hl->next) { mongoc_topology_description_add_server (&topology->description, hl->host_and_port, &id); mongoc_topology_scanner_add (topology->scanner, hl, id); } if (! topology->single_threaded) { _mongoc_topology_background_thread_start (topology); } return topology; } /* *------------------------------------------------------------------------- * * mongoc_topology_destroy -- * * Free the memory associated with this topology object. * * Returns: * None. * * Side effects: * @topology will be cleaned up. * *------------------------------------------------------------------------- */ void mongoc_topology_destroy (mongoc_topology_t *topology) { if (!topology) { return; } _mongoc_topology_background_thread_stop (topology); mongoc_uri_destroy (topology->uri); mongoc_topology_description_destroy(&topology->description); mongoc_topology_scanner_destroy (topology->scanner); mongoc_cond_destroy (&topology->cond_client); mongoc_cond_destroy (&topology->cond_server); mongoc_mutex_destroy (&topology->mutex); bson_free(topology); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_run_scanner -- * * Not threadsafe, the expectation is that we're either single * threaded or only the background thread runs scans. * * Crank the underlying scanner until we've timed out or finished. * * Returns: * true if there is more work to do, false otherwise * *-------------------------------------------------------------------------- */ static bool _mongoc_topology_run_scanner (mongoc_topology_t *topology, int64_t work_msec) { int64_t now; int64_t expire_at; bool keep_going = true; now = bson_get_monotonic_time (); expire_at = now + (work_msec * 1000); /* while there is more work to do and we haven't timed out */ while (keep_going && now <= expire_at) { keep_going = mongoc_topology_scanner_work (topology->scanner, (expire_at - now) / 1000); if (keep_going) { now = bson_get_monotonic_time (); } } return keep_going; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_do_blocking_scan -- * * Monitoring entry for single-threaded use case. Assumes the caller * has checked that it's the right time to scan. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_do_blocking_scan (mongoc_topology_t *topology, bson_error_t *error) { mongoc_topology_scanner_start (topology->scanner, topology->connect_timeout_msec, true); while (_mongoc_topology_run_scanner (topology, topology->connect_timeout_msec)) {} /* Aggregate all scanner errors, if any */ mongoc_topology_scanner_sum_errors (topology->scanner, error); /* "retired" nodes can be checked again in the next scan */ mongoc_topology_scanner_reset (topology->scanner); topology->last_scan = bson_get_monotonic_time (); topology->stale = false; } /* *------------------------------------------------------------------------- * * mongoc_topology_select -- * * Selects a server description for an operation based on @optype * and @read_prefs. * * NOTE: this method returns a copy of the original server * description. Callers must own and clean up this copy. * * NOTE: this method locks and unlocks @topology's mutex. * * Parameters: * @topology: The topology. * @optype: Whether we are selecting for a read or write operation. * @read_prefs: Required, the read preferences for the command. * @local_threshold_ms: Maximum latency *beyond* the nearest server * among which to randomly select servers. See Server Selection * Spec. * @error: Required, out pointer for error info. * * Returns: * A mongoc_server_description_t, or NULL on failure, in which case * @error will be set. * * Side effects: * @error may be set. * *------------------------------------------------------------------------- */ mongoc_server_description_t * mongoc_topology_select (mongoc_topology_t *topology, mongoc_ss_optype_t optype, const mongoc_read_prefs_t *read_prefs, int64_t local_threshold_ms, bson_error_t *error) { int r; mongoc_server_description_t *selected_server = NULL; bool try_once; int64_t sleep_usec; bool tried_once; bson_error_t scanner_error = { 0 }; /* These names come from the Server Selection Spec pseudocode */ int64_t loop_start; /* when we entered this function */ int64_t loop_end; /* when we last completed a loop (single-threaded) */ int64_t scan_ready; /* the soonest we can do a blocking scan */ int64_t next_update; /* the latest we must do a blocking scan */ int64_t expire_at; /* when server selection timeout expires */ BSON_ASSERT (topology); try_once = topology->server_selection_try_once; loop_start = loop_end = bson_get_monotonic_time (); expire_at = loop_start + ((int64_t) topology->server_selection_timeout_msec * 1000); if (topology->single_threaded) { tried_once = false; next_update = topology->last_scan + topology->heartbeat_msec * 1000; if (next_update < loop_start) { /* we must scan now */ topology->stale = true; } /* until we find a server or time out */ for (;;) { if (topology->stale) { /* how soon are we allowed to scan? */ scan_ready = topology->last_scan + MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS * 1000; if (scan_ready > expire_at && !try_once) { /* selection timeout will expire before min heartbeat passes */ bson_set_error(error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "No suitable servers found: " "`minheartbeatfrequencyms` not reached yet"); goto FAIL; } sleep_usec = scan_ready - loop_end; if (sleep_usec > 0) { _mongoc_usleep (sleep_usec); } /* takes up to connectTimeoutMS. sets "last_scan", clears "stale" */ _mongoc_topology_do_blocking_scan (topology, &scanner_error); tried_once = true; } selected_server = mongoc_topology_description_select(&topology->description, optype, read_prefs, local_threshold_ms); if (selected_server) { return mongoc_server_description_new_copy(selected_server); } topology->stale = true; if (try_once) { if (tried_once) { if (scanner_error.code) { bson_set_error(error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "No suitable servers found " "(`serverselectiontryonce` set): %s", scanner_error.message); } else { bson_set_error(error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "No suitable servers found " "(`serverselectiontryonce` set)"); } goto FAIL; } } else { loop_end = bson_get_monotonic_time (); if (loop_end > expire_at) { /* no time left in server_selection_timeout_msec */ bson_set_error(error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "No suitable servers found: " "`serverselectiontimeoutms` timed out"); goto FAIL; } } } } /* With background thread */ /* we break out when we've found a server or timed out */ for (;;) { mongoc_mutex_lock (&topology->mutex); selected_server = mongoc_topology_description_select(&topology->description, optype, read_prefs, local_threshold_ms); if (! selected_server) { _mongoc_topology_request_scan (topology); r = mongoc_cond_timedwait (&topology->cond_client, &topology->mutex, (expire_at - loop_start) / 1000); mongoc_mutex_unlock (&topology->mutex); #ifdef _WIN32 if (r == WSAETIMEDOUT) { #else if (r == ETIMEDOUT) { #endif /* handle timeouts */ bson_set_error(error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "Timed out trying to select a server"); goto FAIL; } else if (r) { bson_set_error(error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "Unknown error '%d' received while waiting on thread condition", r); goto FAIL; } loop_start = bson_get_monotonic_time (); if (loop_start > expire_at) { bson_set_error(error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "Timed out trying to select a server"); goto FAIL; } } else { selected_server = mongoc_server_description_new_copy(selected_server); mongoc_mutex_unlock (&topology->mutex); return selected_server; } } FAIL: topology->stale = true; return NULL; } /* *------------------------------------------------------------------------- * * mongoc_topology_server_by_id -- * * Get the server description for @id, if that server is present * in @description. Otherwise, return NULL and fill out the optional * @error. * * NOTE: this method returns a copy of the original server * description. Callers must own and clean up this copy. * * NOTE: this method locks and unlocks @topology's mutex. * * Returns: * A mongoc_server_description_t, or NULL. * * Side effects: * Fills out optional @error if server not found. * *------------------------------------------------------------------------- */ mongoc_server_description_t * mongoc_topology_server_by_id (mongoc_topology_t *topology, uint32_t id, bson_error_t *error) { mongoc_server_description_t *sd; mongoc_mutex_lock (&topology->mutex); sd = mongoc_server_description_new_copy ( mongoc_topology_description_server_by_id (&topology->description, id, error)); mongoc_mutex_unlock (&topology->mutex); return sd; } /* *------------------------------------------------------------------------- * * mongoc_topology_get_server_type -- * * Get the topology type, and the server type for @id, if that server * is present in @description. Otherwise, return false and fill out * the optional @error. * * NOTE: this method locks and unlocks @topology's mutex. * * Returns: * True on success. * * Side effects: * Fills out optional @error if server not found. * *------------------------------------------------------------------------- */ bool mongoc_topology_get_server_type ( mongoc_topology_t *topology, uint32_t id, mongoc_topology_description_type_t *topology_type /* OUT */, mongoc_server_description_type_t *server_type /* OUT */, bson_error_t *error) { mongoc_server_description_t *sd; bool ret = false; BSON_ASSERT (topology); BSON_ASSERT (topology_type); BSON_ASSERT (server_type); mongoc_mutex_lock (&topology->mutex); sd = mongoc_topology_description_server_by_id (&topology->description, id, error); if (sd) { *topology_type = topology->description.type; *server_type = sd->type; ret = true; } mongoc_mutex_unlock (&topology->mutex); return ret; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_request_scan -- * * Non-locking variant * *-------------------------------------------------------------------------- */ static void _mongoc_topology_request_scan (mongoc_topology_t *topology) { topology->scan_requested = true; mongoc_cond_signal (&topology->cond_server); } /* *-------------------------------------------------------------------------- * * mongoc_topology_request_scan -- * * Used from within the driver to request an immediate topology check. * * NOTE: this method locks and unlocks @topology's mutex. * *-------------------------------------------------------------------------- */ void mongoc_topology_request_scan (mongoc_topology_t *topology) { mongoc_mutex_lock (&topology->mutex); _mongoc_topology_request_scan (topology); mongoc_mutex_unlock (&topology->mutex); } /* *-------------------------------------------------------------------------- * * mongoc_topology_invalidate_server -- * * Invalidate the given server after receiving a network error in * another part of the client. * * NOTE: this method uses @topology's mutex. * *-------------------------------------------------------------------------- */ void mongoc_topology_invalidate_server (mongoc_topology_t *topology, uint32_t id) { mongoc_mutex_lock (&topology->mutex); mongoc_topology_description_invalidate_server (&topology->description, id); mongoc_mutex_unlock (&topology->mutex); } /* *-------------------------------------------------------------------------- * * mongoc_topology_server_timestamp -- * * Return the topology's scanner's timestamp for the given server, * or -1 if there is no scanner node for the given server. * * NOTE: this method uses @topology's mutex. * * Returns: * Timestamp, or -1 * *-------------------------------------------------------------------------- */ int64_t mongoc_topology_server_timestamp (mongoc_topology_t *topology, uint32_t id) { mongoc_topology_scanner_node_t *node; int64_t timestamp = -1; mongoc_mutex_lock (&topology->mutex); node = mongoc_topology_scanner_get_node (topology->scanner, id); if (node) { timestamp = node->timestamp; } mongoc_mutex_unlock (&topology->mutex); return timestamp; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_run_background -- * * The background topology monitoring thread runs in this loop. * * NOTE: this method uses @topology's mutex. * *-------------------------------------------------------------------------- */ static void * _mongoc_topology_run_background (void *data) { mongoc_topology_t *topology; int64_t now; int64_t last_scan; int64_t timeout; int64_t force_timeout; int r; BSON_ASSERT (data); last_scan = 0; topology = (mongoc_topology_t *)data; /* we exit this loop when shutdown_requested, or on error */ for (;;) { /* unlocked after starting a scan or after breaking out of the loop */ mongoc_mutex_lock (&topology->mutex); /* we exit this loop on error, or when we should scan immediately */ for (;;) { if (topology->shutdown_requested) goto DONE; now = bson_get_monotonic_time (); if (last_scan == 0) { /* set up the "last scan" as exactly long enough to force an * immediate scan on the first pass */ last_scan = now - (topology->heartbeat_msec * 1000); } timeout = topology->heartbeat_msec - ((now - last_scan) / 1000); /* if someone's specifically asked for a scan, use a shorter interval */ if (topology->scan_requested) { force_timeout = MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS - ((now - last_scan) / 1000); timeout = BSON_MIN (timeout, force_timeout); } /* if we can start scanning, do so immediately */ if (timeout <= 0) { mongoc_topology_scanner_start (topology->scanner, topology->connect_timeout_msec, false); break; } else { /* otherwise wait until someone: * o requests a scan * o we time out * o requests a shutdown */ r = mongoc_cond_timedwait (&topology->cond_server, &topology->mutex, timeout); #ifdef _WIN32 if (! (r == 0 || r == WSAETIMEDOUT)) { #else if (! (r == 0 || r == ETIMEDOUT)) { #endif /* handle errors */ goto DONE; } /* if we timed out, or were woken up, check if it's time to scan * again, or bail out */ } } topology->scan_requested = false; topology->scanning = true; /* scanning locks and unlocks the mutex itself until the scan is done */ mongoc_mutex_unlock (&topology->mutex); while (_mongoc_topology_run_scanner (topology, topology->connect_timeout_msec)) {} mongoc_mutex_lock (&topology->mutex); /* "retired" nodes can be checked again in the next scan */ mongoc_topology_scanner_reset (topology->scanner); topology->last_scan = bson_get_monotonic_time (); topology->scanning = false; mongoc_mutex_unlock (&topology->mutex); last_scan = bson_get_monotonic_time(); } DONE: mongoc_mutex_unlock (&topology->mutex); return NULL; } /* *-------------------------------------------------------------------------- * * mongoc_topology_background_thread_start -- * * Start the topology background thread running. This should only be * called once per pool. If clients are created separately (not * through a pool) the SDAM logic will not be run in a background * thread. * * NOTE: this method uses @topology's mutex. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_background_thread_start (mongoc_topology_t *topology) { bool launch_thread = true; if (topology->single_threaded) { return; } mongoc_mutex_lock (&topology->mutex); if (topology->bg_thread_state != MONGOC_TOPOLOGY_BG_OFF) launch_thread = false; topology->bg_thread_state = MONGOC_TOPOLOGY_BG_RUNNING; mongoc_mutex_unlock (&topology->mutex); if (launch_thread) { mongoc_thread_create (&topology->thread, _mongoc_topology_run_background, topology); } } /* *-------------------------------------------------------------------------- * * mongoc_topology_background_thread_stop -- * * Stop the topology background thread. Called by the owning pool at * its destruction. * * NOTE: this method uses @topology's mutex. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_background_thread_stop (mongoc_topology_t *topology) { bool join_thread = false; if (topology->single_threaded) { return; } mongoc_mutex_lock (&topology->mutex); if (topology->bg_thread_state == MONGOC_TOPOLOGY_BG_RUNNING) { /* if the background thread is running, request a shutdown and signal the * thread */ topology->shutdown_requested = true; mongoc_cond_signal (&topology->cond_server); topology->bg_thread_state = MONGOC_TOPOLOGY_BG_SHUTTING_DOWN; join_thread = true; } else if (topology->bg_thread_state == MONGOC_TOPOLOGY_BG_SHUTTING_DOWN) { /* if we're mid shutdown, wait until it shuts down */ while (topology->bg_thread_state != MONGOC_TOPOLOGY_BG_OFF) { mongoc_cond_wait (&topology->cond_client, &topology->mutex); } } else { /* nothing to do if it's already off */ } mongoc_mutex_unlock (&topology->mutex); if (join_thread) { /* if we're joining the thread, wait for it to come back and broadcast * all listeners */ mongoc_thread_join (topology->thread); mongoc_cond_broadcast (&topology->cond_client); } } libmongoc-1.3.1/src/mongoc/mongoc-trace.h000066400000000000000000000043661264720626300203060ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_TRACE_PRIVATE_H #define MONGOC_TRACE_PRIVATE_H #include #include #include "mongoc-log.h" #include "mongoc-log-private.h" BSON_BEGIN_DECLS #ifdef MONGOC_TRACE #define TRACE(msg, ...) \ do { mongoc_log(MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, "TRACE: %s():%d " msg, BSON_FUNC, __LINE__, __VA_ARGS__); } while (0) #define ENTRY do { mongoc_log(MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, "ENTRY: %s():%d", BSON_FUNC, __LINE__); } while (0) #define EXIT do { mongoc_log(MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, " EXIT: %s():%d", BSON_FUNC, __LINE__); return; } while (0) #define RETURN(ret) do { mongoc_log(MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, " EXIT: %s():%d", BSON_FUNC, __LINE__); return ret; } while (0) #define GOTO(label) do { mongoc_log(MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, " GOTO: %s():%d %s", BSON_FUNC, __LINE__, #label); goto label; } while (0) #define DUMP_BYTES(_n, _b, _l) do { \ mongoc_log(MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, "TRACE: %s():%d %s = %p [%d]", BSON_FUNC, __LINE__, #_n, _b, (int)_l); \ mongoc_log_trace_bytes(MONGOC_LOG_DOMAIN, _b, _l); \ } while (0) #define DUMP_IOVEC(_n, _iov, _iovcnt) do { \ mongoc_log(MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, "TRACE: %s():%d %s = %p [%d]", BSON_FUNC, __LINE__, #_n, _iov, (int)_iovcnt); \ mongoc_log_trace_iovec(MONGOC_LOG_DOMAIN, _iov, _iovcnt); \ } while (0) #else #define TRACE(msg,...) #define ENTRY #define EXIT return #define RETURN(ret) return ret #define GOTO(label) goto label #define DUMP_BYTES(_n, _b, _l) #define DUMP_IOVEC(_n, _iov, _iovcnt) #endif BSON_END_DECLS #endif /* MONGOC_TRACE_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-uri-private.h000066400000000000000000000062471264720626300214570ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_URI_PRIVATE_H #define MONGOC_URI_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include "mongoc-uri.h" BSON_BEGIN_DECLS void mongoc_uri_lowercase_hostname ( const char *src, char *buf /* OUT */, int len); void mongoc_uri_append_host ( mongoc_uri_t *uri, const char *host, uint16_t port); bool mongoc_uri_parse_host ( mongoc_uri_t *uri, const char *str); bool mongoc_uri_set_username ( mongoc_uri_t *uri, const char *username); bool mongoc_uri_set_password ( mongoc_uri_t *uri, const char *password); bool mongoc_uri_set_database ( mongoc_uri_t *uri, const char *database); bool mongoc_uri_set_auth_source ( mongoc_uri_t *uri, const char *value); bool mongoc_uri_option_is_int32 (const char *key); bool mongoc_uri_option_is_bool (const char *key); bool mongoc_uri_option_is_utf8 (const char *key); int32_t mongoc_uri_get_option_as_int32 (const mongoc_uri_t *uri, const char *option, int32_t fallback); bool mongoc_uri_get_option_as_bool (const mongoc_uri_t *uri, const char *option, bool fallback); const char* mongoc_uri_get_option_as_utf8 (const mongoc_uri_t *uri, const char *option, const char *fallback); bool mongoc_uri_set_option_as_int32 ( mongoc_uri_t *uri, const char *option, int32_t value); bool mongoc_uri_set_option_as_bool ( mongoc_uri_t *uri, const char *option, bool value); bool mongoc_uri_set_option_as_utf8 ( mongoc_uri_t *uri, const char *option, const char *value); BSON_END_DECLS #endif /* MONGOC_URI_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-uri.c000066400000000000000000001142401264720626300177730ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include /* strcasecmp on windows */ #include "mongoc-util-private.h" #include "mongoc-host-list.h" #include "mongoc-host-list-private.h" #include "mongoc-log.h" #include "mongoc-socket.h" #include "mongoc-uri-private.h" #include "mongoc-read-concern-private.h" #include "mongoc-write-concern-private.h" struct _mongoc_uri_t { char *str; mongoc_host_list_t *hosts; char *username; char *password; char *database; bson_t options; bson_t credentials; mongoc_read_prefs_t *read_prefs; mongoc_read_concern_t *read_concern; mongoc_write_concern_t *write_concern; }; static void mongoc_uri_do_unescape (char **str) { char *tmp; if ((tmp = *str)) { *str = mongoc_uri_unescape(tmp); bson_free(tmp); } } void mongoc_uri_lowercase_hostname (const char *src, char *buf /* OUT */, int len) { bson_unichar_t c; const char *iter; char *buf_iter; /* TODO: this code only accepts ascii, and assumes that lowercased chars are the same width as originals */ for (iter = src, buf_iter = buf; iter && *iter && (c = bson_utf8_get_char(iter)) && buf_iter - buf < len; iter = bson_utf8_next_char(iter), buf_iter++) { assert(c < 128); *buf_iter = tolower(c); } } void mongoc_uri_append_host (mongoc_uri_t *uri, const char *host, uint16_t port) { mongoc_host_list_t *iter; mongoc_host_list_t *link_; link_ = (mongoc_host_list_t *)bson_malloc0(sizeof *link_); mongoc_uri_lowercase_hostname(host, link_->host, sizeof link_->host); if (strchr (host, ':')) { bson_snprintf (link_->host_and_port, sizeof link_->host_and_port, "[%s]:%hu", host, port); link_->family = AF_INET6; } else { bson_snprintf (link_->host_and_port, sizeof link_->host_and_port, "%s:%hu", host, port); link_->family = strstr (host, ".sock") ? AF_UNIX : AF_INET; } link_->host_and_port[sizeof link_->host_and_port - 1] = '\0'; link_->port = port; if ((iter = uri->hosts)) { for (; iter && iter->next; iter = iter->next) {} iter->next = link_; } else { uri->hosts = link_; } } /* *-------------------------------------------------------------------------- * * scan_to_unichar -- * * Scans 'str' until either a character matching 'match' is found, * until one of the characters in 'terminators' is encountered, or * until we reach the end of 'str'. * * NOTE: 'terminators' may not include multibyte UTF-8 characters. * * Returns: * If 'match' is found, returns a copy of the section of 'str' before * that character. Otherwise, returns NULL. * * Side Effects: * If 'match' is found, sets 'end' to begin at the matching character * in 'str'. * *-------------------------------------------------------------------------- */ static char * scan_to_unichar (const char *str, bson_unichar_t match, const char *terminators, const char **end) { bson_unichar_t c; const char *iter; for (iter = str; iter && *iter && (c = bson_utf8_get_char(iter)); iter = bson_utf8_next_char(iter)) { if (c == match) { *end = iter; return bson_strndup(str, iter - str); } else if (c == '\\') { iter = bson_utf8_next_char(iter); if (!bson_utf8_get_char(iter)) { break; } } else { const char *term_iter; for (term_iter = terminators; *term_iter; term_iter++) { if (c == *term_iter) { return NULL; } } } } return NULL; } static bool mongoc_uri_parse_scheme (const char *str, const char **end) { if (!!strncmp(str, "mongodb://", 10)) { return false; } *end = str + 10; return true; } static bool mongoc_uri_parse_userpass (mongoc_uri_t *uri, const char *str, const char **end) { bool ret = false; const char *end_userpass; const char *end_user; char *s; if ((s = scan_to_unichar(str, '@', "", &end_userpass))) { if ((uri->username = scan_to_unichar(s, ':', "", &end_user))) { uri->password = bson_strdup(end_user + 1); } else { uri->username = bson_strndup(str, end_userpass - str); uri->password = NULL; } mongoc_uri_do_unescape(&uri->username); mongoc_uri_do_unescape(&uri->password); *end = end_userpass + 1; bson_free(s); ret = true; } else { ret = true; } return ret; } static bool mongoc_uri_parse_port (uint16_t *port, const char *str) { unsigned long ul_port; ul_port = strtoul (str, NULL, 10); if (ul_port == 0 || ul_port > UINT16_MAX) { /* Parse error or port number out of range. mongod prohibits port 0. */ return false; } *port = (uint16_t)ul_port; return true; } static bool mongoc_uri_parse_host6 (mongoc_uri_t *uri, const char *str) { uint16_t port = MONGOC_DEFAULT_PORT; const char *portstr; const char *end_host; char *hostname; if ((portstr = strrchr (str, ':')) && !strstr (portstr, "]")) { if (!mongoc_uri_parse_port(&port, portstr + 1)) { return false; } } hostname = scan_to_unichar (str + 1, ']', "", &end_host); mongoc_uri_do_unescape (&hostname); if (!hostname) { return false; } mongoc_uri_append_host (uri, hostname, port); bson_free (hostname); return true; } bool mongoc_uri_parse_host (mongoc_uri_t *uri, const char *str) { uint16_t port; const char *end_host; char *hostname; if (*str == '[' && strchr (str, ']')) { return mongoc_uri_parse_host6 (uri, str); } if ((hostname = scan_to_unichar(str, ':', "?/,", &end_host))) { end_host++; if (!mongoc_uri_parse_port(&port, end_host)) { bson_free (hostname); return false; } } else { hostname = bson_strdup(str); port = MONGOC_DEFAULT_PORT; } mongoc_uri_do_unescape(&hostname); if (!hostname) { /* invalid */ bson_free (hostname); return false; } mongoc_uri_append_host(uri, hostname, port); bson_free(hostname); return true; } bool _mongoc_host_list_from_string (mongoc_host_list_t *host_list, const char *host_and_port) { bool rval = false; char *uri_str = NULL; mongoc_uri_t *uri = NULL; const mongoc_host_list_t *uri_hl; BSON_ASSERT (host_list); BSON_ASSERT (host_and_port); uri_str = bson_strdup_printf("mongodb://%s/", host_and_port); if (! uri_str) goto CLEANUP; uri = mongoc_uri_new(uri_str); if (! uri) goto CLEANUP; uri_hl = mongoc_uri_get_hosts(uri); if (uri_hl->next) goto CLEANUP; memcpy(host_list, uri_hl, sizeof(*uri_hl)); rval = true; CLEANUP: bson_free(uri_str); if (uri) mongoc_uri_destroy(uri); return rval; } static bool mongoc_uri_parse_hosts (mongoc_uri_t *uri, const char *str, const char **end) { bool ret = false; const char *end_hostport; const char *sock; const char *tmp; char *s; /* * Parsing the series of hosts is a lot more complicated than you might * imagine. This is due to some characters being both separators as well as * valid characters within the "hostname". In particularly, we can have file * paths to specify paths to UNIX domain sockets. We impose the restriction * that they must be suffixed with ".sock" to simplify the parsing. * * You can separate hosts and file system paths to UNIX domain sockets with * ",". * * When you reach a "/" or "?" that is not part of a file-system path, we * have completed our parsing of hosts. */ again: if (((*str == '/') && (sock = strstr(str, ".sock"))) && (!(tmp = strstr(str, ",")) || (tmp > sock)) && (!(tmp = strstr(str, "?")) || (tmp > sock))) { s = bson_strndup(str, sock + 5 - str); if (!mongoc_uri_parse_host(uri, s)) { bson_free(s); return false; } bson_free(s); str = sock + 5; ret = true; if (*str == ',') { str++; goto again; } } else if ((s = scan_to_unichar(str, ',', "/", &end_hostport))) { if (!mongoc_uri_parse_host(uri, s)) { bson_free(s); return false; } bson_free(s); str = end_hostport + 1; ret = true; goto again; } else if ((s = scan_to_unichar(str, '/', "", &end_hostport)) || (s = scan_to_unichar(str, '?', "", &end_hostport))) { if (!mongoc_uri_parse_host(uri, s)) { bson_free(s); return false; } bson_free(s); *end = end_hostport; return true; } else if (*str) { if (!mongoc_uri_parse_host(uri, str)) { return false; } *end = str + strlen(str); return true; } return ret; } static bool mongoc_uri_parse_database (mongoc_uri_t *uri, const char *str, const char **end) { const char *end_database; if ((uri->database = scan_to_unichar(str, '?', "", &end_database))) { *end = end_database; } else if (*str) { uri->database = bson_strdup(str); *end = str + strlen(str); } mongoc_uri_do_unescape(&uri->database); if (!uri->database) { /* invalid */ return false; } return true; } static bool mongoc_uri_parse_auth_mechanism_properties (mongoc_uri_t *uri, const char *str) { char *field; char *value; const char *end_scan; bson_t properties; bson_init(&properties); /* build up the properties document */ while ((field = scan_to_unichar(str, ':', "&", &end_scan))) { str = end_scan + 1; if (!(value = scan_to_unichar(str, ',', ":&", &end_scan))) { value = bson_strdup(str); str = ""; } else { str = end_scan + 1; } bson_append_utf8(&properties, field, -1, value, -1); bson_free(field); bson_free(value); } /* append our auth properties to our credentials */ bson_append_document(&uri->credentials, "mechanismProperties", -1, (const bson_t *)&properties); return true; } static void mongoc_uri_parse_tags (mongoc_uri_t *uri, /* IN */ const char *str) /* IN */ { const char *end_keyval; const char *end_key; bson_t b; char *keyval; char *key; bson_init(&b); again: if ((keyval = scan_to_unichar(str, ',', "", &end_keyval))) { if ((key = scan_to_unichar(keyval, ':', "", &end_key))) { bson_append_utf8(&b, key, -1, end_key + 1, -1); bson_free(key); } bson_free(keyval); str = end_keyval + 1; goto again; } else { if ((key = scan_to_unichar(str, ':', "", &end_key))) { bson_append_utf8(&b, key, -1, end_key + 1, -1); bson_free(key); } } mongoc_read_prefs_add_tag(uri->read_prefs, &b); bson_destroy(&b); } /* *-------------------------------------------------------------------------- * * mongoc_uri_bson_append_or_replace_key -- * * * Appends 'option' to the end of 'options' if not already set. * * Since we cannot grow utf8 strings inline, we have to allocate a temporary * bson variable and splice in the new value if the key is already set. * * NOTE: This function keeps the order of the BSON keys. * * NOTE: 'option' is case*in*sensitive. * * *-------------------------------------------------------------------------- */ static void mongoc_uri_bson_append_or_replace_key (bson_t *options, const char *option, const char *value) { bson_iter_t iter; bool found = false; if (bson_iter_init (&iter, options)) { bson_t tmp = BSON_INITIALIZER; while (bson_iter_next (&iter)) { const bson_value_t *bvalue; if (!strcasecmp(bson_iter_key (&iter), option)) { bson_append_utf8(&tmp, option, -1, value, -1); found = true; continue; } bvalue = bson_iter_value (&iter); BSON_APPEND_VALUE (&tmp, bson_iter_key (&iter), bvalue); } if (! found) { bson_append_utf8(&tmp, option, -1, value, -1); } bson_destroy (options); bson_copy_to (&tmp, options); bson_destroy (&tmp); } } bool mongoc_uri_option_is_int32 (const char *key) { return !strcasecmp(key, "connecttimeoutms") || !strcasecmp(key, "heartbeatfrequencyms") || !strcasecmp(key, "serverselectiontimeoutms") || !strcasecmp(key, "socketcheckintervalms") || !strcasecmp(key, "sockettimeoutms") || !strcasecmp(key, "maxpoolsize") || !strcasecmp(key, "minpoolsize") || !strcasecmp(key, "maxidletimems") || !strcasecmp(key, "waitqueuemultiple") || !strcasecmp(key, "waitqueuetimeoutms") || !strcasecmp(key, "wtimeoutms"); } bool mongoc_uri_option_is_bool (const char *key) { return !strcasecmp(key, "canonicalizeHostname") || !strcasecmp(key, "journal") || !strcasecmp(key, "safe") || !strcasecmp(key, "serverSelectionTryOnce") || !strcasecmp(key, "slaveok") || !strcasecmp(key, "ssl"); } bool mongoc_uri_option_is_utf8 (const char *key) { if (mongoc_uri_option_is_bool(key) || mongoc_uri_option_is_int32(key)) { return false; } if (!strcasecmp(key, "readpreferencetags") || !strcasecmp(key, "authmechanismproperties")) { return false; } if (!strcasecmp(key, "username") || !strcasecmp(key, "password") || !strcasecmp(key, "authsource") || !strcasecmp(key, "database")) { return false; } return true; } static bool mongoc_uri_parse_option (mongoc_uri_t *uri, const char *str) { int32_t v_int; const char *end_key; char *key = NULL; char *value = NULL; bool ret = false; if (!(key = scan_to_unichar(str, '=', "", &end_key))) { goto CLEANUP; } value = bson_strdup(end_key + 1); mongoc_uri_do_unescape(&value); if (!value) { /* do_unescape detected invalid UTF-8 and freed value */ goto CLEANUP; } if (mongoc_uri_option_is_int32(key)) { v_int = (int) strtol (value, NULL, 10); BSON_APPEND_INT32 (&uri->options, key, v_int); } else if (!strcasecmp(key, "w")) { if (*value == '-' || isdigit(*value)) { v_int = (int) strtol (value, NULL, 10); BSON_APPEND_INT32 (&uri->options, "w", v_int); } else if (0 == strcasecmp (value, "majority")) { BSON_APPEND_UTF8 (&uri->options, "w", "majority"); } else if (*value) { BSON_APPEND_UTF8 (&uri->options, "w", value); } } else if (mongoc_uri_option_is_bool(key)) { bson_append_bool (&uri->options, key, -1, (0 == strcasecmp (value, "true")) || (0 == strcasecmp (value, "t")) || (0 == strcmp (value, "1"))); } else if (!strcasecmp(key, "readpreferencetags")) { mongoc_uri_parse_tags(uri, value); } else if (!strcasecmp(key, "authmechanism") || !strcasecmp(key, "authsource")) { bson_append_utf8(&uri->credentials, key, -1, value, -1); } else if (!strcasecmp(key, "readconcernlevel")) { mongoc_read_concern_set_level (uri->read_concern, value); } else if (!strcasecmp(key, "authmechanismproperties")) { if (!mongoc_uri_parse_auth_mechanism_properties(uri, value)) { bson_free(key); bson_free(value); return false; } } else { bson_append_utf8(&uri->options, key, -1, value, -1); } ret = true; CLEANUP: bson_free(key); bson_free(value); return ret; } static bool mongoc_uri_parse_options (mongoc_uri_t *uri, const char *str) { const char *end_option; char *option; again: if ((option = scan_to_unichar(str, '&', "", &end_option))) { if (!mongoc_uri_parse_option(uri, option)) { bson_free(option); return false; } bson_free(option); str = end_option + 1; goto again; } else if (*str) { if (!mongoc_uri_parse_option(uri, str)) { return false; } } return true; } static bool mongoc_uri_finalize_auth (mongoc_uri_t *uri) { bson_iter_t iter; const char *source = NULL; const char *mechanism = mongoc_uri_get_auth_mechanism(uri); if (bson_iter_init_find_case(&iter, &uri->credentials, "authSource")) { source = bson_iter_utf8(&iter, NULL); } /* authSource with GSSAPI or X509 should always be external */ if (mechanism) { if (!strcasecmp(mechanism, "GSSAPI") || !strcasecmp(mechanism, "MONGODB-X509")) { if (source) { if (strcasecmp(source, "$external")) { return false; } } else { bson_append_utf8(&uri->credentials, "authsource", -1, "$external", -1); } } } return true; } static bool mongoc_uri_parse (mongoc_uri_t *uri, const char *str) { if (!mongoc_uri_parse_scheme(str, &str)) { return false; } if (!*str || !mongoc_uri_parse_userpass(uri, str, &str)) { return false; } if (!*str || !mongoc_uri_parse_hosts(uri, str, &str)) { return false; } switch (*str) { case '/': str++; if (*str && !mongoc_uri_parse_database(uri, str, &str)) { return false; } if (!*str) { break; } /* Fall through */ case '?': str++; if (*str && !mongoc_uri_parse_options(uri, str)) { return false; } break; default: break; } return mongoc_uri_finalize_auth(uri); } const mongoc_host_list_t * mongoc_uri_get_hosts (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->hosts; } const char * mongoc_uri_get_replica_set (const mongoc_uri_t *uri) { bson_iter_t iter; BSON_ASSERT (uri); if (bson_iter_init_find_case(&iter, &uri->options, "replicaSet") && BSON_ITER_HOLDS_UTF8(&iter)) { return bson_iter_utf8(&iter, NULL); } return NULL; } const bson_t * mongoc_uri_get_credentials (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return &uri->credentials; } const char * mongoc_uri_get_auth_mechanism (const mongoc_uri_t *uri) { bson_iter_t iter; BSON_ASSERT (uri); if (bson_iter_init_find_case (&iter, &uri->credentials, "authMechanism") && BSON_ITER_HOLDS_UTF8 (&iter)) { return bson_iter_utf8 (&iter, NULL); } return NULL; } bool mongoc_uri_get_mechanism_properties (const mongoc_uri_t *uri, bson_t *properties) { bson_iter_t iter; if (!uri) { return false; } if (bson_iter_init_find_case (&iter, &uri->credentials, "mechanismProperties") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { uint32_t len = 0; const uint8_t *data = NULL; bson_iter_document (&iter, &len, &data); bson_init_static (properties, data, len); return true; } return false; } static void _mongoc_uri_assign_read_prefs_mode (mongoc_uri_t *uri) /* IN */ { const char *str; bson_iter_t iter; BSON_ASSERT(uri); if (mongoc_uri_get_option_as_bool (uri, "slaveok", false)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY_PREFERRED); } if (bson_iter_init_find_case(&iter, &uri->options, "readpreference") && BSON_ITER_HOLDS_UTF8(&iter)) { str = bson_iter_utf8(&iter, NULL); if (0 == strcasecmp("primary", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_PRIMARY); } else if (0 == strcasecmp("primarypreferred", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_PRIMARY_PREFERRED); } else if (0 == strcasecmp("secondary", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY); } else if (0 == strcasecmp("secondarypreferred", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY_PREFERRED); } else if (0 == strcasecmp("nearest", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_NEAREST); } else { MONGOC_WARNING("Unsupported readPreference value [readPreference=%s].", str); } } /* Warn on conflict, since read preference will be validated later */ if (mongoc_read_prefs_get_mode(uri->read_prefs) == MONGOC_READ_PRIMARY && !bson_empty(mongoc_read_prefs_get_tags(uri->read_prefs))) { MONGOC_WARNING("Primary read preference mode conflicts with tags."); } } static void _mongoc_uri_build_write_concern (mongoc_uri_t *uri) /* IN */ { mongoc_write_concern_t *write_concern; const char *str; bson_iter_t iter; int32_t wtimeoutms; int value; BSON_ASSERT (uri); write_concern = mongoc_write_concern_new (); if (bson_iter_init_find_case (&iter, &uri->options, "safe") && BSON_ITER_HOLDS_BOOL (&iter)) { mongoc_write_concern_set_w (write_concern, bson_iter_bool (&iter) ? 1 : MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED); } wtimeoutms = mongoc_uri_get_option_as_int32(uri, "wtimeoutms", 0); if (bson_iter_init_find_case (&iter, &uri->options, "journal") && BSON_ITER_HOLDS_BOOL (&iter)) { mongoc_write_concern_set_journal (write_concern, bson_iter_bool (&iter)); } if (bson_iter_init_find_case (&iter, &uri->options, "w")) { if (BSON_ITER_HOLDS_INT32 (&iter)) { value = bson_iter_int32 (&iter); switch (value) { case MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED: case MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED: /* Warn on conflict, since write concern will be validated later */ if (mongoc_write_concern_get_journal(write_concern)) { MONGOC_WARNING("Journal conflicts with w value [w=%d].", value); } mongoc_write_concern_set_w(write_concern, value); break; default: if (value > 0) { mongoc_write_concern_set_w (write_concern, value); if (value > 1) { mongoc_write_concern_set_wtimeout (write_concern, wtimeoutms); } break; } MONGOC_WARNING ("Unsupported w value [w=%d].", value); break; } } else if (BSON_ITER_HOLDS_UTF8 (&iter)) { str = bson_iter_utf8 (&iter, NULL); if (0 == strcasecmp ("majority", str)) { mongoc_write_concern_set_wmajority (write_concern, wtimeoutms); } else { mongoc_write_concern_set_wtag (write_concern, str); mongoc_write_concern_set_wtimeout (write_concern, wtimeoutms); } } else { BSON_ASSERT (false); } } uri->write_concern = write_concern; } mongoc_uri_t * mongoc_uri_new (const char *uri_string) { mongoc_uri_t *uri; uri = (mongoc_uri_t *)bson_malloc0(sizeof *uri); bson_init(&uri->options); bson_init(&uri->credentials); /* Initialize read_prefs since tag parsing may add to it */ uri->read_prefs = mongoc_read_prefs_new(MONGOC_READ_PRIMARY); /* Initialize empty read_concern */ uri->read_concern = mongoc_read_concern_new (); if (!uri_string) { uri_string = "mongodb://127.0.0.1/"; } if (!mongoc_uri_parse(uri, uri_string)) { mongoc_uri_destroy(uri); return NULL; } uri->str = bson_strdup(uri_string); _mongoc_uri_assign_read_prefs_mode(uri); if (!mongoc_read_prefs_is_valid(uri->read_prefs)) { mongoc_uri_destroy(uri); return NULL; } _mongoc_uri_build_write_concern (uri); if (!_mongoc_write_concern_is_valid(uri->write_concern)) { mongoc_uri_destroy(uri); return NULL; } return uri; } mongoc_uri_t * mongoc_uri_new_for_host_port (const char *hostname, uint16_t port) { mongoc_uri_t *uri; char *str; BSON_ASSERT (hostname); BSON_ASSERT (port); str = bson_strdup_printf("mongodb://%s:%hu/", hostname, port); uri = mongoc_uri_new(str); bson_free(str); return uri; } const char * mongoc_uri_get_username (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->username; } bool mongoc_uri_set_username (mongoc_uri_t *uri, const char *username) { size_t len; BSON_ASSERT (username); len = strlen(username); if (!bson_utf8_validate (username, len, false)) { return false; } if (uri->username) { bson_free (uri->username); } uri->username = bson_strdup (username); return true; } const char * mongoc_uri_get_password (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->password; } bool mongoc_uri_set_password (mongoc_uri_t *uri, const char *password) { size_t len; BSON_ASSERT (password); len = strlen(password); if (!bson_utf8_validate (password, len, false)) { return false; } if (uri->password) { bson_free (uri->password); } uri->password = bson_strdup (password); return true; } const char * mongoc_uri_get_database (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->database; } bool mongoc_uri_set_database (mongoc_uri_t *uri, const char *database) { size_t len; BSON_ASSERT (database); len = strlen(database); if (!bson_utf8_validate (database, len, false)) { return false; } if (uri->database) { bson_free (uri->database); } uri->database = bson_strdup(database); return true; } const char * mongoc_uri_get_auth_source (const mongoc_uri_t *uri) { bson_iter_t iter; BSON_ASSERT (uri); if (bson_iter_init_find_case(&iter, &uri->credentials, "authSource")) { return bson_iter_utf8(&iter, NULL); } return uri->database ? uri->database : "admin"; } bool mongoc_uri_set_auth_source (mongoc_uri_t *uri, const char *value) { size_t len; BSON_ASSERT (value); len = strlen(value); if (!bson_utf8_validate (value, len, false)) { return false; } mongoc_uri_bson_append_or_replace_key (&uri->credentials, "authSource", value); return true; } const bson_t * mongoc_uri_get_options (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return &uri->options; } void mongoc_uri_destroy (mongoc_uri_t *uri) { if (uri) { _mongoc_host_list_destroy_all (uri->hosts); bson_free(uri->str); bson_free(uri->database); bson_free(uri->username); bson_destroy(&uri->options); bson_destroy(&uri->credentials); mongoc_read_prefs_destroy(uri->read_prefs); mongoc_read_concern_destroy(uri->read_concern); mongoc_write_concern_destroy(uri->write_concern); if (uri->password) { bson_zero_free(uri->password, strlen(uri->password)); } bson_free(uri); } } mongoc_uri_t * mongoc_uri_copy (const mongoc_uri_t *uri) { mongoc_uri_t *copy; mongoc_host_list_t *iter; BSON_ASSERT (uri); copy = (mongoc_uri_t *)bson_malloc0(sizeof (*copy)); copy->str = bson_strdup (uri->str); copy->username = bson_strdup (uri->username); copy->password = bson_strdup (uri->password); copy->database = bson_strdup (uri->database); copy->read_prefs = mongoc_read_prefs_copy (uri->read_prefs); copy->read_concern = mongoc_read_concern_copy (uri->read_concern); copy->write_concern = mongoc_write_concern_copy (uri->write_concern); for (iter = uri->hosts; iter; iter = iter->next) { mongoc_uri_append_host (copy, iter->host, iter->port); } bson_copy_to (&uri->options, ©->options); bson_copy_to (&uri->credentials, ©->credentials); return copy; } const char * mongoc_uri_get_string (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->str; } const bson_t * mongoc_uri_get_read_prefs (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return mongoc_read_prefs_get_tags(uri->read_prefs); } /* *-------------------------------------------------------------------------- * * mongoc_uri_unescape -- * * Escapes an UTF-8 encoded string containing URI escaped segments * such as %20. * * It is a programming error to call this function with a string * that is not UTF-8 encoded! * * Returns: * A newly allocated string that should be freed with bson_free(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * mongoc_uri_unescape (const char *escaped_string) { bson_unichar_t c; bson_string_t *str; unsigned int hex = 0; const char *ptr; const char *end; size_t len; BSON_ASSERT (escaped_string); len = strlen(escaped_string); /* * Double check that this is a UTF-8 valid string. Bail out if necessary. */ if (!bson_utf8_validate(escaped_string, len, false)) { MONGOC_WARNING("%s(): escaped_string contains invalid UTF-8", BSON_FUNC); return NULL; } ptr = escaped_string; end = ptr + len; str = bson_string_new(NULL); for (; *ptr; ptr = bson_utf8_next_char(ptr)) { c = bson_utf8_get_char(ptr); switch (c) { case '%': if (((end - ptr) < 2) || !isxdigit(ptr[1]) || !isxdigit(ptr[2]) || #ifdef _MSC_VER (1 != sscanf_s(&ptr[1], "%02x", &hex)) || #else (1 != sscanf(&ptr[1], "%02x", &hex)) || #endif !isprint(hex)) { bson_string_free(str, true); return NULL; } bson_string_append_c(str, hex); ptr += 2; break; default: bson_string_append_unichar(str, c); break; } } return bson_string_free(str, false); } const mongoc_read_prefs_t * mongoc_uri_get_read_prefs_t (const mongoc_uri_t *uri) /* IN */ { BSON_ASSERT (uri); return uri->read_prefs; } const mongoc_read_concern_t * mongoc_uri_get_read_concern (const mongoc_uri_t *uri) /* IN */ { BSON_ASSERT (uri); return uri->read_concern; } const mongoc_write_concern_t * mongoc_uri_get_write_concern (const mongoc_uri_t *uri) /* IN */ { BSON_ASSERT (uri); return uri->write_concern; } bool mongoc_uri_get_ssl (const mongoc_uri_t *uri) /* IN */ { bson_iter_t iter; BSON_ASSERT (uri); return (bson_iter_init_find_case (&iter, &uri->options, "ssl") && BSON_ITER_HOLDS_BOOL (&iter) && bson_iter_bool (&iter)); } /* *-------------------------------------------------------------------------- * * mongoc_uri_get_option_as_int32 -- * * Checks if the URI 'option' is set and of correct type (int32). * The special value '0' is considered as "unset". * This is so users can provide * sprintf(mongodb://localhost/?option=%d, myvalue) style connection strings, * and still apply default values. * * If not set, or set to invalid type, 'fallback' is returned. * * NOTE: 'option' is case*in*sensitive. * * Returns: * The value of 'option' if available as int32 (and not 0), or 'fallback'. * *-------------------------------------------------------------------------- */ int32_t mongoc_uri_get_option_as_int32(const mongoc_uri_t *uri, const char *option, int32_t fallback) { const bson_t *options; bson_iter_t iter; int32_t retval = fallback; if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option) && BSON_ITER_HOLDS_INT32 (&iter)) { if (!(retval = bson_iter_int32(&iter))) { retval = fallback; } } return retval; } /* *-------------------------------------------------------------------------- * * mongoc_uri_set_option_as_int32 -- * * Sets a URI option 'after the fact'. Allows users to set individual * URI options without passing them as a connection string. * * Only allows a set of known options to be set. * @see mongoc_uri_option_is_int32 (). * * Does in-place-update of the option BSON if 'option' is already set. * Appends the option to the end otherwise. * * NOTE: If 'option' is already set, and is of invalid type, this * function will return false. * * NOTE: 'option' is case*in*sensitive. * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ bool mongoc_uri_set_option_as_int32(mongoc_uri_t *uri, const char *option, int32_t value) { const bson_t *options; bson_iter_t iter; BSON_ASSERT (option); if (!mongoc_uri_option_is_int32 (option)) { return false; } if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option)) { if (BSON_ITER_HOLDS_INT32 (&iter)) { bson_iter_overwrite_int32 (&iter, value); return true; } else { return false; } } bson_append_int32(&uri->options, option, -1, value); return true; } /* *-------------------------------------------------------------------------- * * mongoc_uri_get_option_as_bool -- * * Checks if the URI 'option' is set and of correct type (bool). * * If not set, or set to invalid type, 'fallback' is returned. * * NOTE: 'option' is case*in*sensitive. * * Returns: * The value of 'option' if available as bool, or 'fallback'. * *-------------------------------------------------------------------------- */ bool mongoc_uri_get_option_as_bool (const mongoc_uri_t *uri, const char *option, bool fallback) { const bson_t *options; bson_iter_t iter; if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option) && BSON_ITER_HOLDS_BOOL (&iter)) { return bson_iter_bool (&iter); } return fallback; } /* *-------------------------------------------------------------------------- * * mongoc_uri_set_option_as_bool -- * * Sets a URI option 'after the fact'. Allows users to set individual * URI options without passing them as a connection string. * * Only allows a set of known options to be set. * @see mongoc_uri_option_is_bool (). * * Does in-place-update of the option BSON if 'option' is already set. * Appends the option to the end otherwise. * * NOTE: If 'option' is already set, and is of invalid type, this * function will return false. * * NOTE: 'option' is case*in*sensitive. * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ bool mongoc_uri_set_option_as_bool(mongoc_uri_t *uri, const char *option, bool value) { const bson_t *options; bson_iter_t iter; BSON_ASSERT (option); if (!mongoc_uri_option_is_bool (option)) { return false; } if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option)) { if (BSON_ITER_HOLDS_BOOL (&iter)) { bson_iter_overwrite_bool (&iter, value); return true; } else { return false; } } bson_append_bool(&uri->options, option, -1, value); return true; } /* *-------------------------------------------------------------------------- * * mongoc_uri_get_option_as_utf8 -- * * Checks if the URI 'option' is set and of correct type (utf8). * * If not set, or set to invalid type, 'fallback' is returned. * * NOTE: 'option' is case*in*sensitive. * * Returns: * The value of 'option' if available as utf8, or 'fallback'. * *-------------------------------------------------------------------------- */ const char* mongoc_uri_get_option_as_utf8 (const mongoc_uri_t *uri, const char *option, const char *fallback) { const bson_t *options; bson_iter_t iter; if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option) && BSON_ITER_HOLDS_UTF8 (&iter)) { return bson_iter_utf8 (&iter, NULL); } return fallback; } /* *-------------------------------------------------------------------------- * * mongoc_uri_set_option_as_utf8 -- * * Sets a URI option 'after the fact'. Allows users to set individual * URI options without passing them as a connection string. * * Only allows a set of known options to be set. * @see mongoc_uri_option_is_utf8 (). * * If the option is not already set, this function will append it to the end * of the options bson. * NOTE: If the option is already set the entire options bson will be * overwritten, containing the new option=value (at the same position). * * NOTE: If 'option' is already set, and is of invalid type, this * function will return false. * * NOTE: 'option' must be valid utf8. * * NOTE: 'option' is case*in*sensitive. * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ bool mongoc_uri_set_option_as_utf8(mongoc_uri_t *uri, const char *option, const char *value) { size_t len; BSON_ASSERT (option); len = strlen(value); if (!bson_utf8_validate (value, len, false)) { return false; } if (!mongoc_uri_option_is_utf8 (option)) { return false; } mongoc_uri_bson_append_or_replace_key (&uri->options, option, value); return true; } libmongoc-1.3.1/src/mongoc/mongoc-uri.h000066400000000000000000000064641264720626300200100ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_URI_H #define MONGOC_URI_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include #include "mongoc-host-list.h" #include "mongoc-read-prefs.h" #include "mongoc-read-concern.h" #include "mongoc-write-concern.h" #ifndef MONGOC_DEFAULT_PORT # define MONGOC_DEFAULT_PORT 27017 #endif BSON_BEGIN_DECLS typedef struct _mongoc_uri_t mongoc_uri_t; mongoc_uri_t *mongoc_uri_copy (const mongoc_uri_t *uri); void mongoc_uri_destroy (mongoc_uri_t *uri); mongoc_uri_t *mongoc_uri_new (const char *uri_string) BSON_GNUC_WARN_UNUSED_RESULT; mongoc_uri_t *mongoc_uri_new_for_host_port (const char *hostname, uint16_t port) BSON_GNUC_WARN_UNUSED_RESULT; const mongoc_host_list_t *mongoc_uri_get_hosts (const mongoc_uri_t *uri); const char *mongoc_uri_get_database (const mongoc_uri_t *uri); const bson_t *mongoc_uri_get_options (const mongoc_uri_t *uri); const char *mongoc_uri_get_password (const mongoc_uri_t *uri); const bson_t *mongoc_uri_get_read_prefs (const mongoc_uri_t *uri) BSON_GNUC_DEPRECATED_FOR (mongoc_uri_get_read_prefs_t); const char *mongoc_uri_get_replica_set (const mongoc_uri_t *uri); const char *mongoc_uri_get_string (const mongoc_uri_t *uri); const char *mongoc_uri_get_username (const mongoc_uri_t *uri); const bson_t *mongoc_uri_get_credentials (const mongoc_uri_t *uri); const char *mongoc_uri_get_auth_source (const mongoc_uri_t *uri); const char *mongoc_uri_get_auth_mechanism (const mongoc_uri_t *uri); bool mongoc_uri_get_mechanism_properties (const mongoc_uri_t *uri, bson_t *properties); bool mongoc_uri_get_ssl (const mongoc_uri_t *uri); char *mongoc_uri_unescape (const char *escaped_string); const mongoc_read_prefs_t * mongoc_uri_get_read_prefs_t (const mongoc_uri_t *uri); const mongoc_write_concern_t *mongoc_uri_get_write_concern (const mongoc_uri_t *uri); const mongoc_read_concern_t *mongoc_uri_get_read_concern (const mongoc_uri_t *uri); BSON_END_DECLS #endif /* MONGOC_URI_H */ libmongoc-1.3.1/src/mongoc/mongoc-util-private.h000066400000000000000000000030051264720626300216220ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_UTIL_PRIVATE_H #define MONGOC_UTIL_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include /* string comparison functions for Windows */ #ifdef _WIN32 # define strcasecmp _stricmp # define strncasecmp _strnicmp #endif /* Suppress CWE-252 ("Unchecked return value") warnings for things we can't deal with */ #if defined(__GNUC__) && __GNUC__ >= 4 # define _ignore_value(x) (({ __typeof__ (x) __x = (x); (void) __x; })) #else # define _ignore_value(x) ((void) (x)) #endif BSON_BEGIN_DECLS char *_mongoc_hex_md5 (const char *input); void _mongoc_usleep (int64_t usec); const char *_mongoc_get_command_name (const bson_t *command); void _mongoc_get_db_name (const char *ns, char *db /* OUT */); void _mongoc_bson_destroy_if_set (bson_t *bson); BSON_END_DECLS #endif /* MONGOC_UTIL_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-util.c000066400000000000000000000042611264720626300201520ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-util-private.h" #include "mongoc-client.h" char * _mongoc_hex_md5 (const char *input) { uint8_t digest[16]; bson_md5_t md5; char digest_str[33]; int i; bson_md5_init(&md5); bson_md5_append(&md5, (const uint8_t *)input, (uint32_t)strlen(input)); bson_md5_finish(&md5, digest); for (i = 0; i < sizeof digest; i++) { bson_snprintf(&digest_str[i*2], 3, "%02x", digest[i]); } digest_str[sizeof digest_str - 1] = '\0'; return bson_strdup(digest_str); } void _mongoc_usleep (int64_t usec) { #ifdef _WIN32 LARGE_INTEGER ft; HANDLE timer; BSON_ASSERT (usec >= 0); ft.QuadPart = -(10 * usec); timer = CreateWaitableTimer(NULL, true, NULL); SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); WaitForSingleObject(timer, INFINITE); CloseHandle(timer); #else BSON_ASSERT (usec >= 0); usleep ((useconds_t) usec); #endif } const char * _mongoc_get_command_name (const bson_t *command) { bson_iter_t iter; BSON_ASSERT (command); if (!bson_iter_init (&iter, command) || !bson_iter_next (&iter)) { return NULL; } return bson_iter_key (&iter); } void _mongoc_get_db_name (const char *ns, char *db /* OUT */) { size_t dblen; const char *dot; BSON_ASSERT (ns); dot = strstr (ns, "."); if (dot) { dblen = BSON_MIN (dot - ns + 1, MONGOC_NAMESPACE_MAX); bson_strncpy (db, ns, dblen); } else { bson_strncpy (db, ns, MONGOC_NAMESPACE_MAX); } } void _mongoc_bson_destroy_if_set (bson_t *bson) { if (bson) { bson_destroy (bson); } } libmongoc-1.3.1/src/mongoc/mongoc-version-functions.c000066400000000000000000000033021264720626300226630ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-version.h" #include "mongoc-version-functions.h" /** * mongoc_get_major_version: * * Helper function to return the runtime major version of the library. */ int mongoc_get_major_version (void) { return MONGOC_MAJOR_VERSION; } /** * mongoc_get_minor_version: * * Helper function to return the runtime minor version of the library. */ int mongoc_get_minor_version (void) { return MONGOC_MINOR_VERSION; } /** * mongoc_get_micro_version: * * Helper function to return the runtime micro version of the library. */ int mongoc_get_micro_version (void) { return MONGOC_MICRO_VERSION; } /** * mongoc_get_version: * * Helper function to return the runtime string version of the library. */ const char * mongoc_get_version (void) { return MONGOC_VERSION_S; } /** * mongoc_check_version: * * True if libmongoc's version is greater than or equal to the required * version. */ bool mongoc_check_version (int required_major, int required_minor, int required_micro) { return MONGOC_CHECK_VERSION(required_major, required_minor, required_micro); } libmongoc-1.3.1/src/mongoc/mongoc-version-functions.h000066400000000000000000000022101264720626300226650ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #ifndef MONGOC_VERSION_FUNCTIONS_H #define MONGOC_VERSION_FUNCTIONS_H #include "bson.h" /* for "bool" */ int mongoc_get_major_version (void); int mongoc_get_minor_version (void); int mongoc_get_micro_version (void); const char *mongoc_get_version (void); bool mongoc_check_version (int required_major, int required_minor, int required_micro); #endif /* MONGOC_VERSION_FUNCTIONS_H */ libmongoc-1.3.1/src/mongoc/mongoc-version.h.in000066400000000000000000000050301264720626300212670ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #ifndef MONGOC_VERSION_H #define MONGOC_VERSION_H /** * MONGOC_MAJOR_VERSION: * * MONGOC major version component (e.g. 1 if %MONGOC_VERSION is 1.2.3) */ #define MONGOC_MAJOR_VERSION (@MONGOC_MAJOR_VERSION@) /** * MONGOC_MINOR_VERSION: * * MONGOC minor version component (e.g. 2 if %MONGOC_VERSION is 1.2.3) */ #define MONGOC_MINOR_VERSION (@MONGOC_MINOR_VERSION@) /** * MONGOC_MICRO_VERSION: * * MONGOC micro version component (e.g. 3 if %MONGOC_VERSION is 1.2.3) */ #define MONGOC_MICRO_VERSION (@MONGOC_MICRO_VERSION@) /** * MONGOC_PRERELEASE_VERSION: * * MONGOC prerelease version component (e.g. rc0 if %MONGOC_VERSION is 1.2.3-rc0) */ #define MONGOC_PRERELEASE_VERSION (@MONGOC_PRERELEASE_VERSION@) /** * MONGOC_VERSION: * * MONGOC version. */ #define MONGOC_VERSION (@MONGOC_VERSION@) /** * MONGOC_VERSION_S: * * MONGOC version, encoded as a string, useful for printing and * concatenation. */ #define MONGOC_VERSION_S "@MONGOC_VERSION@" /** * MONGOC_VERSION_HEX: * * MONGOC version, encoded as an hexadecimal number, useful for * integer comparisons. */ #define MONGOC_VERSION_HEX (MONGOC_MAJOR_VERSION << 24 | \ MONGOC_MINOR_VERSION << 16 | \ MONGOC_MICRO_VERSION << 8) /** * MONGOC_CHECK_VERSION: * @major: required major version * @minor: required minor version * @micro: required micro version * * Compile-time version checking. Evaluates to %TRUE if the version * of MONGOC is greater than the required one. */ #define MONGOC_CHECK_VERSION(major,minor,micro) \ (MONGOC_MAJOR_VERSION > (major) || \ (MONGOC_MAJOR_VERSION == (major) && MONGOC_MINOR_VERSION > (minor)) || \ (MONGOC_MAJOR_VERSION == (major) && MONGOC_MINOR_VERSION == (minor) && \ MONGOC_MICRO_VERSION >= (micro))) #endif /* MONGOC_VERSION_H */ libmongoc-1.3.1/src/mongoc/mongoc-write-command-private.h000066400000000000000000000140271264720626300234210ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_WRITE_COMMAND_PRIVATE_H #define MONGOC_WRITE_COMMAND_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include #include "mongoc-client.h" #include "mongoc-error.h" #include "mongoc-write-concern.h" #include "mongoc-server-stream-private.h" BSON_BEGIN_DECLS #define MONGOC_WRITE_COMMAND_DELETE 0 #define MONGOC_WRITE_COMMAND_INSERT 1 #define MONGOC_WRITE_COMMAND_UPDATE 2 typedef enum { MONGOC_BYPASS_DOCUMENT_VALIDATION_FALSE = 0, MONGOC_BYPASS_DOCUMENT_VALIDATION_TRUE = 1 << 0, MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT = 1 << 1, } mongoc_write_bypass_document_validation_t; struct _mongoc_bulk_write_flags_t { bool ordered; mongoc_write_bypass_document_validation_t bypass_document_validation; }; typedef struct { int type; uint32_t hint; bson_t *documents; uint32_t n_documents; mongoc_bulk_write_flags_t flags; union { struct { bool multi; } delete_; struct { bool allow_bulk_op_insert; } insert; } u; } mongoc_write_command_t; typedef struct { /* true after a legacy update prevents us from calculating nModified */ bool omit_nModified; uint32_t nInserted; uint32_t nMatched; uint32_t nModified; uint32_t nRemoved; uint32_t nUpserted; /* like [{"index": int, "_id": value}, ...] */ bson_t writeErrors; /* like [{"index": int, "code": int, "errmsg": str}, ...] */ bson_t upserted; /* like [{"code": 64, "errmsg": "duplicate"}, ...] */ uint32_t n_writeConcernErrors; bson_t writeConcernErrors; bool failed; bson_error_t error; uint32_t upsert_append_count; } mongoc_write_result_t; void _mongoc_write_command_destroy (mongoc_write_command_t *command); void _mongoc_write_command_init_insert (mongoc_write_command_t *command, const bson_t *document, mongoc_bulk_write_flags_t flags, bool allow_bulk_op_insert); void _mongoc_write_command_init_delete (mongoc_write_command_t *command, const bson_t *selectors, bool multi, mongoc_bulk_write_flags_t flags); void _mongoc_write_command_init_update (mongoc_write_command_t *command, const bson_t *selector, const bson_t *update, bool upsert, bool multi, mongoc_bulk_write_flags_t flags); void _mongoc_write_command_insert_append (mongoc_write_command_t *command, const bson_t *document); void _mongoc_write_command_update_append (mongoc_write_command_t *command, const bson_t *selector, const bson_t *update, bool upsert, bool multi); void _mongoc_write_command_delete_append (mongoc_write_command_t *command, const bson_t *selector); void _mongoc_write_command_execute (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, const mongoc_write_concern_t *write_concern, uint32_t offset, mongoc_write_result_t *result); void _mongoc_write_result_init (mongoc_write_result_t *result); void _mongoc_write_result_merge (mongoc_write_result_t *result, mongoc_write_command_t *command, const bson_t *reply, uint32_t offset); void _mongoc_write_result_merge_legacy (mongoc_write_result_t *result, mongoc_write_command_t *command, const bson_t *reply, mongoc_error_code_t default_code, uint32_t offset); bool _mongoc_write_result_complete (mongoc_write_result_t *result, bson_t *reply, bson_error_t *error); void _mongoc_write_result_destroy (mongoc_write_result_t *result); BSON_END_DECLS #endif /* MONGOC_WRITE_COMMAND_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-write-command.c000066400000000000000000001352031264720626300217440ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-client-private.h" #include "mongoc-error.h" #include "mongoc-trace.h" #include "mongoc-write-command-private.h" #include "mongoc-write-concern-private.h" #include "mongoc-util-private.h" /* * TODO: * * - Remove error parameter to ops, favor result->error. */ #define WRITE_CONCERN_DOC(wc) \ (wc && _mongoc_write_concern_needs_gle ((wc))) ? \ (_mongoc_write_concern_get_bson((mongoc_write_concern_t*)(wc))) : \ (&gEmptyWriteConcern) typedef void (*mongoc_write_op_t) (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, const mongoc_write_concern_t *write_concern, uint32_t offset, mongoc_write_result_t *result, bson_error_t *error); static bson_t gEmptyWriteConcern = BSON_INITIALIZER; /* indexed by MONGOC_WRITE_COMMAND_DELETE, INSERT, UPDATE */ static const char *gCommandNames[] = { "delete", "insert", "update"}; static const char *gCommandFields[] = { "deletes", "documents", "updates"}; static int32_t _mongoc_write_result_merge_arrays (uint32_t offset, mongoc_write_result_t *result, bson_t *dest, bson_iter_t *iter); void _mongoc_write_command_insert_append (mongoc_write_command_t *command, const bson_t *document) { const char *key; bson_iter_t iter; bson_oid_t oid; bson_t tmp; char keydata [16]; ENTRY; BSON_ASSERT (command); BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_INSERT); BSON_ASSERT (document); BSON_ASSERT (document->len >= 5); key = NULL; bson_uint32_to_string (command->n_documents, &key, keydata, sizeof keydata); BSON_ASSERT (key); /* * If the document does not contain an "_id" field, we need to generate * a new oid for "_id". */ if (!bson_iter_init_find (&iter, document, "_id")) { bson_init (&tmp); bson_oid_init (&oid, NULL); BSON_APPEND_OID (&tmp, "_id", &oid); bson_concat (&tmp, document); BSON_APPEND_DOCUMENT (command->documents, key, &tmp); bson_destroy (&tmp); } else { BSON_APPEND_DOCUMENT (command->documents, key, document); } command->n_documents++; EXIT; } void _mongoc_write_command_update_append (mongoc_write_command_t *command, const bson_t *selector, const bson_t *update, bool upsert, bool multi) { const char *key; char keydata [16]; bson_t doc; ENTRY; BSON_ASSERT (command); BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_UPDATE); BSON_ASSERT (selector && update); bson_init (&doc); BSON_APPEND_DOCUMENT (&doc, "q", selector); BSON_APPEND_DOCUMENT (&doc, "u", update); BSON_APPEND_BOOL (&doc, "upsert", upsert); BSON_APPEND_BOOL (&doc, "multi", multi); key = NULL; bson_uint32_to_string (command->n_documents, &key, keydata, sizeof keydata); BSON_ASSERT (key); BSON_APPEND_DOCUMENT (command->documents, key, &doc); command->n_documents++; bson_destroy (&doc); EXIT; } void _mongoc_write_command_delete_append (mongoc_write_command_t *command, const bson_t *selector) { const char *key; char keydata [16]; bson_t doc; ENTRY; BSON_ASSERT (command); BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_DELETE); BSON_ASSERT (selector); BSON_ASSERT (selector->len >= 5); bson_init (&doc); BSON_APPEND_DOCUMENT (&doc, "q", selector); BSON_APPEND_INT32 (&doc, "limit", command->u.delete_.multi ? 0 : 1); key = NULL; bson_uint32_to_string (command->n_documents, &key, keydata, sizeof keydata); BSON_ASSERT (key); BSON_APPEND_DOCUMENT (command->documents, key, &doc); command->n_documents++; bson_destroy (&doc); EXIT; } void _mongoc_write_command_init_insert (mongoc_write_command_t *command, /* IN */ const bson_t *document, /* IN */ mongoc_bulk_write_flags_t flags, /* IN */ bool allow_bulk_op_insert) /* IN */ { ENTRY; BSON_ASSERT (command); command->type = MONGOC_WRITE_COMMAND_INSERT; command->documents = bson_new (); command->n_documents = 0; command->flags = flags; command->u.insert.allow_bulk_op_insert = (uint8_t)allow_bulk_op_insert; command->hint = 0; /* must handle NULL document from mongoc_collection_insert_bulk */ if (document) { _mongoc_write_command_insert_append (command, document); } EXIT; } void _mongoc_write_command_init_delete (mongoc_write_command_t *command, /* IN */ const bson_t *selector, /* IN */ bool multi, /* IN */ mongoc_bulk_write_flags_t flags) /* IN */ { ENTRY; BSON_ASSERT (command); BSON_ASSERT (selector); command->type = MONGOC_WRITE_COMMAND_DELETE; command->documents = bson_new (); command->n_documents = 0; command->u.delete_.multi = (uint8_t)multi; command->flags = flags; command->hint = 0; _mongoc_write_command_delete_append (command, selector); EXIT; } void _mongoc_write_command_init_update (mongoc_write_command_t *command, /* IN */ const bson_t *selector, /* IN */ const bson_t *update, /* IN */ bool upsert, /* IN */ bool multi, /* IN */ mongoc_bulk_write_flags_t flags) /* IN */ { ENTRY; BSON_ASSERT (command); BSON_ASSERT (selector); BSON_ASSERT (update); command->type = MONGOC_WRITE_COMMAND_UPDATE; command->documents = bson_new (); command->n_documents = 0; command->flags = flags; command->hint = 0; _mongoc_write_command_update_append (command, selector, update, upsert, multi); EXIT; } static void _mongoc_write_command_delete_legacy (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, const mongoc_write_concern_t *write_concern, uint32_t offset, mongoc_write_result_t *result, bson_error_t *error) { const uint8_t *data; mongoc_rpc_t rpc; bson_iter_t iter; bson_iter_t q_iter; uint32_t len; bson_t *gle = NULL; char ns [MONGOC_NAMESPACE_MAX + 1]; bool r; ENTRY; BSON_ASSERT (command); BSON_ASSERT (client); BSON_ASSERT (database); BSON_ASSERT (server_stream); BSON_ASSERT (collection); r = bson_iter_init (&iter, command->documents); if (!r) { BSON_ASSERT (false); EXIT; } if (!command->n_documents || !bson_iter_next (&iter)) { bson_set_error (error, MONGOC_ERROR_COLLECTION, MONGOC_ERROR_COLLECTION_DELETE_FAILED, "Cannot do an empty delete."); result->failed = true; EXIT; } bson_snprintf (ns, sizeof ns, "%s.%s", database, collection); do { /* the document is like { "q": { }, limit: <0 or 1> } */ r = (bson_iter_recurse (&iter, &q_iter) && bson_iter_find (&q_iter, "q") && BSON_ITER_HOLDS_DOCUMENT (&q_iter)); if (!r) { BSON_ASSERT (false); EXIT; } bson_iter_document (&q_iter, &len, &data); BSON_ASSERT (data); BSON_ASSERT (len >= 5); rpc.delete_.msg_len = 0; rpc.delete_.request_id = 0; rpc.delete_.response_to = 0; rpc.delete_.opcode = MONGOC_OPCODE_DELETE; rpc.delete_.zero = 0; rpc.delete_.collection = ns; rpc.delete_.flags = command->u.delete_.multi ? MONGOC_DELETE_NONE : MONGOC_DELETE_SINGLE_REMOVE; rpc.delete_.selector = data; if (!mongoc_cluster_sendv_to_server (&client->cluster, &rpc, 1, server_stream, write_concern, error)) { result->failed = true; EXIT; } if (_mongoc_write_concern_needs_gle (write_concern)) { if (!_mongoc_client_recv_gle (client, server_stream, &gle, error)) { result->failed = true; EXIT; } _mongoc_write_result_merge_legacy ( result, command, gle, MONGOC_ERROR_COLLECTION_DELETE_FAILED, offset); offset++; bson_destroy (gle); } } while (bson_iter_next (&iter)); EXIT; } /* *------------------------------------------------------------------------- * * too_large_error -- * * Fill a bson_error_t and optional bson_t with error info after * receiving a document for bulk insert, update, or remove that is * larger than max_bson_size. * * "err_doc" should be NULL or an empty initialized bson_t. * * Returns: * None. * * Side effects: * "error" and optionally "err_doc" are filled out. * *------------------------------------------------------------------------- */ static void too_large_error (bson_error_t *error, int32_t idx, int32_t len, int32_t max_bson_size, bson_t *err_doc) { /* MongoDB 2.6 uses code 2 for "too large". TODO: see CDRIVER-644 */ const int code = 2; bson_set_error (error, MONGOC_ERROR_BSON, code, "Document %u is too large for the cluster. " "Document is %u bytes, max is %d.", idx, len, max_bson_size); if (err_doc) { BSON_APPEND_INT32 (err_doc, "index", idx); BSON_APPEND_UTF8 (err_doc, "err", error->message); BSON_APPEND_INT32 (err_doc, "code", code); } } static void _mongoc_write_command_insert_legacy (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, const mongoc_write_concern_t *write_concern, uint32_t offset, mongoc_write_result_t *result, bson_error_t *error) { uint32_t current_offset; mongoc_iovec_t *iov; const uint8_t *data; mongoc_rpc_t rpc; bson_iter_t iter; uint32_t len; bson_t *gle = NULL; uint32_t size = 0; bool has_more; char ns [MONGOC_NAMESPACE_MAX + 1]; bool r; uint32_t n_docs_in_batch; uint32_t idx = 0; int32_t max_msg_size; int32_t max_bson_obj_size; bool singly; ENTRY; BSON_ASSERT (command); BSON_ASSERT (client); BSON_ASSERT (database); BSON_ASSERT (server_stream); BSON_ASSERT (collection); BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_INSERT); current_offset = offset; max_bson_obj_size = mongoc_server_stream_max_bson_obj_size (server_stream); max_msg_size = mongoc_server_stream_max_msg_size (server_stream); singly = !command->u.insert.allow_bulk_op_insert; r = bson_iter_init (&iter, command->documents); if (!r) { BSON_ASSERT (false); EXIT; } if (!command->n_documents || !bson_iter_next (&iter)) { bson_set_error (error, MONGOC_ERROR_COLLECTION, MONGOC_ERROR_COLLECTION_INSERT_FAILED, "Cannot do an empty insert."); result->failed = true; EXIT; } bson_snprintf (ns, sizeof ns, "%s.%s", database, collection); iov = (mongoc_iovec_t *)bson_malloc ((sizeof *iov) * command->n_documents); again: has_more = false; n_docs_in_batch = 0; size = (uint32_t)(sizeof (mongoc_rpc_header_t) + 4 + strlen (database) + 1 + strlen (collection) + 1); do { BSON_ASSERT (BSON_ITER_HOLDS_DOCUMENT (&iter)); BSON_ASSERT (n_docs_in_batch <= idx); BSON_ASSERT (idx < command->n_documents); bson_iter_document (&iter, &len, &data); BSON_ASSERT (data); BSON_ASSERT (len >= 5); if (len > max_bson_obj_size) { /* document is too large */ bson_t write_err_doc = BSON_INITIALIZER; too_large_error (error, idx, len, max_bson_obj_size, &write_err_doc); _mongoc_write_result_merge_legacy ( result, command, &write_err_doc, MONGOC_ERROR_COLLECTION_INSERT_FAILED, offset + idx); bson_destroy (&write_err_doc); if (command->flags.ordered) { /* send the batch so far (if any) and return the error */ break; } } else if ((n_docs_in_batch == 1 && singly) || size > (max_msg_size - len)) { /* batch is full, send it and then start the next batch */ has_more = true; break; } else { /* add document to batch and continue building the batch */ iov[n_docs_in_batch].iov_base = (void *) data; iov[n_docs_in_batch].iov_len = len; size += len; n_docs_in_batch++; } idx++; } while (bson_iter_next (&iter)); if (n_docs_in_batch) { rpc.insert.msg_len = 0; rpc.insert.request_id = 0; rpc.insert.response_to = 0; rpc.insert.opcode = MONGOC_OPCODE_INSERT; rpc.insert.flags = ( (command->flags.ordered) ? MONGOC_INSERT_NONE : MONGOC_INSERT_CONTINUE_ON_ERROR); rpc.insert.collection = ns; rpc.insert.documents = iov; rpc.insert.n_documents = n_docs_in_batch; if (!mongoc_cluster_sendv_to_server (&client->cluster, &rpc, 1, server_stream, write_concern, error)) { result->failed = true; GOTO (cleanup); } if (_mongoc_write_concern_needs_gle (write_concern)) { bool err = false; bson_iter_t citer; if (!_mongoc_client_recv_gle (client, server_stream, &gle, error)) { result->failed = true; GOTO (cleanup); } err = (bson_iter_init_find (&citer, gle, "err") && bson_iter_as_bool (&citer)); /* * Overwrite the "n" field since it will be zero. Otherwise, our * merge_legacy code will not know how many we tried in this batch. */ if (!err && bson_iter_init_find (&citer, gle, "n") && BSON_ITER_HOLDS_INT32 (&citer) && !bson_iter_int32 (&citer)) { bson_iter_overwrite_int32 (&citer, n_docs_in_batch); } } } cleanup: if (gle) { _mongoc_write_result_merge_legacy ( result, command, gle, MONGOC_ERROR_COLLECTION_INSERT_FAILED, current_offset); current_offset = offset + idx; bson_destroy (gle); gle = NULL; } if (has_more) { GOTO (again); } bson_free (iov); EXIT; } void _empty_error (mongoc_write_command_t *command, bson_error_t *error) { static const uint32_t codes[] = { MONGOC_ERROR_COLLECTION_DELETE_FAILED, MONGOC_ERROR_COLLECTION_INSERT_FAILED, MONGOC_ERROR_COLLECTION_UPDATE_FAILED }; bson_set_error (error, MONGOC_ERROR_COLLECTION, codes[command->type], "Cannot do an empty %s", gCommandNames[command->type]); } bool _mongoc_write_command_will_overflow (uint32_t len_so_far, uint32_t document_len, uint32_t n_documents_written, int32_t max_bson_size, int32_t max_write_batch_size) { /* max BSON object size + 16k - 2 bytes for ending NUL bytes. * server guarantees there is enough room: SERVER-10643 */ int32_t max_cmd_size = max_bson_size + 16382; BSON_ASSERT (max_bson_size); if (len_so_far + document_len > max_cmd_size) { return true; } else if (max_write_batch_size > 0 && n_documents_written >= max_write_batch_size) { return true; } return false; } static void _mongoc_write_command_update_legacy (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, const mongoc_write_concern_t *write_concern, uint32_t offset, mongoc_write_result_t *result, bson_error_t *error) { mongoc_rpc_t rpc; bson_iter_t iter, subiter, subsubiter; bson_t doc; bool has_update, has_selector, is_upsert; bson_t update, selector; bson_t *gle = NULL; const uint8_t *data = NULL; uint32_t len = 0; size_t err_offset; bool val = false; char ns [MONGOC_NAMESPACE_MAX + 1]; int32_t affected = 0; int vflags = (BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_DOLLAR_KEYS | BSON_VALIDATE_DOT_KEYS); ENTRY; BSON_ASSERT (command); BSON_ASSERT (client); BSON_ASSERT (database); BSON_ASSERT (server_stream); BSON_ASSERT (collection); bson_iter_init (&iter, command->documents); while (bson_iter_next (&iter)) { if (bson_iter_recurse (&iter, &subiter) && bson_iter_find (&subiter, "u") && BSON_ITER_HOLDS_DOCUMENT (&subiter)) { bson_iter_document (&subiter, &len, &data); bson_init_static (&doc, data, len); if (bson_iter_init (&subsubiter, &doc) && bson_iter_next (&subsubiter) && (bson_iter_key (&subsubiter) [0] != '$') && !bson_validate (&doc, (bson_validate_flags_t)vflags, &err_offset)) { result->failed = true; bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "update document is corrupt or contains " "invalid keys including $ or ."); EXIT; } } else { result->failed = true; bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "updates is malformed."); EXIT; } } bson_snprintf (ns, sizeof ns, "%s.%s", database, collection); bson_iter_init (&iter, command->documents); while (bson_iter_next (&iter)) { rpc.update.msg_len = 0; rpc.update.request_id = 0; rpc.update.response_to = 0; rpc.update.opcode = MONGOC_OPCODE_UPDATE; rpc.update.zero = 0; rpc.update.collection = ns; rpc.update.flags = MONGOC_UPDATE_NONE; has_update = false; has_selector = false; is_upsert = false; bson_iter_recurse (&iter, &subiter); while (bson_iter_next (&subiter)) { if (strcmp (bson_iter_key (&subiter), "u") == 0) { bson_iter_document (&subiter, &len, &data); rpc.update.update = data; bson_init_static (&update, data, len); has_update = true; } else if (strcmp (bson_iter_key (&subiter), "q") == 0) { bson_iter_document (&subiter, &len, &data); rpc.update.selector = data; bson_init_static (&selector, data, len); has_selector = true; } else if (strcmp (bson_iter_key (&subiter), "multi") == 0) { val = bson_iter_bool (&subiter); if (val) { rpc.update.flags = (mongoc_update_flags_t)( rpc.update.flags | MONGOC_UPDATE_MULTI_UPDATE); } } else if (strcmp (bson_iter_key (&subiter), "upsert") == 0) { val = bson_iter_bool (&subiter); if (val) { rpc.update.flags = (mongoc_update_flags_t)( rpc.update.flags | MONGOC_UPDATE_UPSERT); } is_upsert = true; } } if (!mongoc_cluster_sendv_to_server (&client->cluster, &rpc, 1, server_stream, write_concern, error)) { result->failed = true; EXIT; } if (_mongoc_write_concern_needs_gle (write_concern)) { if (!_mongoc_client_recv_gle (client, server_stream, &gle, error)) { result->failed = true; EXIT; } if (bson_iter_init_find (&subiter, gle, "n") && BSON_ITER_HOLDS_INT32 (&subiter)) { affected = bson_iter_int32 (&subiter); } /* * CDRIVER-372: * * Versions of MongoDB before 2.6 don't return the _id for an * upsert if _id is not an ObjectId. */ if (is_upsert && affected && !bson_iter_init_find (&subiter, gle, "upserted") && bson_iter_init_find (&subiter, gle, "updatedExisting") && BSON_ITER_HOLDS_BOOL (&subiter) && !bson_iter_bool (&subiter)) { if (has_update && bson_iter_init_find (&subiter, &update, "_id")) { _ignore_value (bson_append_iter (gle, "upserted", 8, &subiter)); } else if (has_selector && bson_iter_init_find (&subiter, &selector, "_id")) { _ignore_value (bson_append_iter (gle, "upserted", 8, &subiter)); } } _mongoc_write_result_merge_legacy ( result, command, gle, MONGOC_ERROR_COLLECTION_UPDATE_FAILED, offset); offset++; bson_destroy (gle); } } EXIT; } static mongoc_write_op_t gLegacyWriteOps[3] = { _mongoc_write_command_delete_legacy, _mongoc_write_command_insert_legacy, _mongoc_write_command_update_legacy }; static void _mongoc_write_command(mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, const mongoc_write_concern_t *write_concern, uint32_t offset, mongoc_write_result_t *result, bson_error_t *error) { const uint8_t *data; bson_iter_t iter; const char *key; uint32_t len = 0; bson_t tmp; bson_t ar; bson_t cmd; bson_t reply; char str [16]; bool has_more; bool ret = false; uint32_t i; int32_t max_bson_obj_size; int32_t max_write_batch_size; int32_t min_wire_version; uint32_t key_len; ENTRY; BSON_ASSERT (command); BSON_ASSERT (client); BSON_ASSERT (database); BSON_ASSERT (server_stream); BSON_ASSERT (collection); max_bson_obj_size = mongoc_server_stream_max_bson_obj_size (server_stream); max_write_batch_size = mongoc_server_stream_max_write_batch_size (server_stream); /* * If we have an unacknowledged write and the server supports the legacy * opcodes, then submit the legacy opcode so we don't need to wait for * a response from the server. */ min_wire_version = server_stream->sd->min_wire_version; if ((min_wire_version == 0) && !_mongoc_write_concern_needs_gle (write_concern)) { if (command->flags.bypass_document_validation != MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set bypassDocumentValidation for unacknowledged writes"); EXIT; } gLegacyWriteOps[command->type] (command, client, server_stream, database, collection, write_concern, offset, result, error); EXIT; } if (!command->n_documents || !bson_iter_init (&iter, command->documents) || !bson_iter_next (&iter)) { _empty_error (command, error); result->failed = true; EXIT; } again: bson_init (&cmd); has_more = false; i = 0; BSON_APPEND_UTF8 (&cmd, gCommandNames[command->type], collection); BSON_APPEND_DOCUMENT (&cmd, "writeConcern", WRITE_CONCERN_DOC (write_concern)); BSON_APPEND_BOOL (&cmd, "ordered", command->flags.ordered); if (command->flags.bypass_document_validation != MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT) { BSON_APPEND_BOOL (&cmd, "bypassDocumentValidation", !!command->flags.bypass_document_validation); } if (!_mongoc_write_command_will_overflow (0, command->documents->len, command->n_documents, max_bson_obj_size, max_write_batch_size)) { /* copy the whole documents buffer as e.g. "updates": [...] */ BSON_APPEND_ARRAY (&cmd, gCommandFields[command->type], command->documents); i = command->n_documents; } else { bson_append_array_begin (&cmd, gCommandFields[command->type], -1, &ar); do { if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { BSON_ASSERT (false); } bson_iter_document (&iter, &len, &data); key_len = (uint32_t) bson_uint32_to_string (i, &key, str, sizeof str); if (_mongoc_write_command_will_overflow (ar.len, key_len + len + 2, i, max_bson_obj_size, max_write_batch_size)) { has_more = true; break; } if (!bson_init_static (&tmp, data, len)) { BSON_ASSERT (false); } BSON_APPEND_DOCUMENT (&ar, key, &tmp); bson_destroy (&tmp); i++; } while (bson_iter_next (&iter)); bson_append_array_end (&cmd, &ar); } if (!i) { too_large_error (error, i, len, max_bson_obj_size, NULL); result->failed = true; ret = false; } else { ret = mongoc_cluster_run_command (&client->cluster, server_stream->stream, MONGOC_QUERY_NONE, database, &cmd, &reply, error); if (!ret) { result->failed = true; } _mongoc_write_result_merge (result, command, &reply, offset); offset += i; bson_destroy (&reply); } bson_destroy (&cmd); if (has_more && (ret || !command->flags.ordered)) { GOTO (again); } EXIT; } void _mongoc_write_command_execute (mongoc_write_command_t *command, /* IN */ mongoc_client_t *client, /* IN */ mongoc_server_stream_t *server_stream, /* IN */ const char *database, /* IN */ const char *collection, /* IN */ const mongoc_write_concern_t *write_concern, /* IN */ uint32_t offset, /* IN */ mongoc_write_result_t *result) /* OUT */ { ENTRY; BSON_ASSERT (command); BSON_ASSERT (client); BSON_ASSERT (server_stream); BSON_ASSERT (database); BSON_ASSERT (collection); BSON_ASSERT (result); if (!write_concern) { write_concern = client->write_concern; } if (!_mongoc_write_concern_is_valid(write_concern)) { bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The write concern is invalid."); result->failed = true; EXIT; } if (!command->hint) { command->hint = server_stream->sd->id; } else { BSON_ASSERT (command->hint == server_stream->sd->id); } if (server_stream->sd->max_wire_version >= WIRE_VERSION_WRITE_CMD) { _mongoc_write_command (command, client, server_stream, database, collection, write_concern, offset, result, &result->error); } else { gLegacyWriteOps[command->type] (command, client, server_stream, database, collection, write_concern, offset, result, &result->error); } EXIT; } void _mongoc_write_command_destroy (mongoc_write_command_t *command) { ENTRY; if (command) { bson_destroy (command->documents); } EXIT; } void _mongoc_write_result_init (mongoc_write_result_t *result) /* IN */ { ENTRY; BSON_ASSERT (result); memset (result, 0, sizeof *result); bson_init (&result->upserted); bson_init (&result->writeConcernErrors); bson_init (&result->writeErrors); EXIT; } void _mongoc_write_result_destroy (mongoc_write_result_t *result) { ENTRY; BSON_ASSERT (result); bson_destroy (&result->upserted); bson_destroy (&result->writeConcernErrors); bson_destroy (&result->writeErrors); EXIT; } static void _mongoc_write_result_append_upsert (mongoc_write_result_t *result, int32_t idx, const bson_value_t *value) { bson_t child; const char *keyptr = NULL; char key[12]; int len; BSON_ASSERT (result); BSON_ASSERT (value); len = (int)bson_uint32_to_string (result->upsert_append_count, &keyptr, key, sizeof key); bson_append_document_begin (&result->upserted, keyptr, len, &child); BSON_APPEND_INT32 (&child, "index", idx); BSON_APPEND_VALUE (&child, "_id", value); bson_append_document_end (&result->upserted, &child); result->upsert_append_count++; } static void _append_write_concern_err_legacy (mongoc_write_result_t *result, const char *err, int32_t code) { char str[16]; const char *key; size_t keylen; bson_t write_concern_error; /* don't set result->failed; record the write concern err and continue */ keylen = bson_uint32_to_string (result->n_writeConcernErrors, &key, str, sizeof str); BSON_ASSERT (keylen < INT_MAX); bson_append_document_begin (&result->writeConcernErrors, key, (int) keylen, &write_concern_error); bson_append_int32 (&write_concern_error, "code", 4, code); bson_append_utf8 (&write_concern_error, "errmsg", 6, err, -1); bson_append_document_end (&result->writeConcernErrors, &write_concern_error); result->n_writeConcernErrors++; } static void _append_write_err_legacy (mongoc_write_result_t *result, const char *err, int32_t code, uint32_t offset) { bson_t holder, write_errors, child; bson_iter_t iter; BSON_ASSERT (code > 0); bson_set_error (&result->error, MONGOC_ERROR_COLLECTION, (uint32_t) code, "%s", err); /* stop processing, if result->ordered */ result->failed = true; bson_init (&holder); bson_append_array_begin (&holder, "0", 1, &write_errors); bson_append_document_begin (&write_errors, "0", 1, &child); /* set error's "index" to 0; fixed up in _mongoc_write_result_merge_arrays */ bson_append_int32 (&child, "index", 5, 0); bson_append_int32 (&child, "code", 4, code); bson_append_utf8 (&child, "errmsg", 6, err, -1); bson_append_document_end (&write_errors, &child); bson_append_array_end (&holder, &write_errors); bson_iter_init (&iter, &holder); bson_iter_next (&iter); _mongoc_write_result_merge_arrays (offset, result, &result->writeErrors, &iter); bson_destroy (&holder); } void _mongoc_write_result_merge_legacy (mongoc_write_result_t *result, /* IN */ mongoc_write_command_t *command, /* IN */ const bson_t *reply, /* IN */ mongoc_error_code_t default_code, uint32_t offset) { const bson_value_t *value; bson_iter_t iter; bson_iter_t ar; bson_iter_t citer; const char *err = NULL; int32_t code = 0; int32_t n = 0; int32_t upsert_idx = 0; ENTRY; BSON_ASSERT (result); BSON_ASSERT (reply); if (bson_iter_init_find (&iter, reply, "n") && BSON_ITER_HOLDS_INT32 (&iter)) { n = bson_iter_int32 (&iter); } if (bson_iter_init_find (&iter, reply, "err") && BSON_ITER_HOLDS_UTF8 (&iter)) { err = bson_iter_utf8 (&iter, NULL); } if (bson_iter_init_find (&iter, reply, "code") && BSON_ITER_HOLDS_INT32 (&iter)) { code = bson_iter_int32 (&iter); } if (code || err) { if (!err) { err = "unknown error"; } if (bson_iter_init_find (&iter, reply, "wtimeout") && bson_iter_as_bool (&iter)) { if (!code) { code = (int32_t) MONGOC_ERROR_WRITE_CONCERN_ERROR; } _append_write_concern_err_legacy (result, err, code); } else { if (!code) { code = (int32_t) default_code; } _append_write_err_legacy (result, err, code, offset); } } switch (command->type) { case MONGOC_WRITE_COMMAND_INSERT: if (n) { result->nInserted += n; } break; case MONGOC_WRITE_COMMAND_DELETE: result->nRemoved += n; break; case MONGOC_WRITE_COMMAND_UPDATE: if (bson_iter_init_find (&iter, reply, "upserted") && !BSON_ITER_HOLDS_ARRAY (&iter)) { result->nUpserted += n; value = bson_iter_value (&iter); _mongoc_write_result_append_upsert (result, offset, value); } else if (bson_iter_init_find (&iter, reply, "upserted") && BSON_ITER_HOLDS_ARRAY (&iter)) { result->nUpserted += n; if (bson_iter_recurse (&iter, &ar)) { while (bson_iter_next (&ar)) { if (BSON_ITER_HOLDS_DOCUMENT (&ar) && bson_iter_recurse (&ar, &citer) && bson_iter_find (&citer, "_id")) { value = bson_iter_value (&citer); _mongoc_write_result_append_upsert (result, offset + upsert_idx, value); upsert_idx++; } } } } else if ((n == 1) && bson_iter_init_find (&iter, reply, "updatedExisting") && BSON_ITER_HOLDS_BOOL (&iter) && !bson_iter_bool (&iter)) { result->nUpserted += n; } else { result->nMatched += n; } break; default: break; } result->omit_nModified = true; EXIT; } static int32_t _mongoc_write_result_merge_arrays (uint32_t offset, mongoc_write_result_t *result, /* IN */ bson_t *dest, /* IN */ bson_iter_t *iter) /* IN */ { const bson_value_t *value; bson_iter_t ar; bson_iter_t citer; int32_t idx; int32_t count = 0; int32_t aridx; bson_t child; const char *keyptr = NULL; char key[12]; int len; ENTRY; BSON_ASSERT (result); BSON_ASSERT (dest); BSON_ASSERT (iter); BSON_ASSERT (BSON_ITER_HOLDS_ARRAY (iter)); aridx = bson_count_keys (dest); if (bson_iter_recurse (iter, &ar)) { while (bson_iter_next (&ar)) { if (BSON_ITER_HOLDS_DOCUMENT (&ar) && bson_iter_recurse (&ar, &citer)) { len = (int)bson_uint32_to_string (aridx++, &keyptr, key, sizeof key); bson_append_document_begin (dest, keyptr, len, &child); while (bson_iter_next (&citer)) { if (BSON_ITER_IS_KEY (&citer, "index")) { idx = bson_iter_int32 (&citer) + offset; BSON_APPEND_INT32 (&child, "index", idx); } else { value = bson_iter_value (&citer); BSON_APPEND_VALUE (&child, bson_iter_key (&citer), value); } } bson_append_document_end (dest, &child); count++; } } } RETURN (count); } void _mongoc_write_result_merge (mongoc_write_result_t *result, /* IN */ mongoc_write_command_t *command, /* IN */ const bson_t *reply, /* IN */ uint32_t offset) { int32_t server_index = 0; const bson_value_t *value; bson_iter_t iter; bson_iter_t citer; bson_iter_t ar; int32_t n_upserted = 0; int32_t affected = 0; ENTRY; BSON_ASSERT (result); BSON_ASSERT (reply); if (bson_iter_init_find (&iter, reply, "n") && BSON_ITER_HOLDS_INT32 (&iter)) { affected = bson_iter_int32 (&iter); } if (bson_iter_init_find (&iter, reply, "writeErrors") && BSON_ITER_HOLDS_ARRAY (&iter) && bson_iter_recurse (&iter, &citer) && bson_iter_next (&citer)) { result->failed = true; } switch (command->type) { case MONGOC_WRITE_COMMAND_INSERT: result->nInserted += affected; break; case MONGOC_WRITE_COMMAND_DELETE: result->nRemoved += affected; break; case MONGOC_WRITE_COMMAND_UPDATE: /* server returns each upserted _id with its index into this batch * look for "upserted": [{"index": 4, "_id": ObjectId()}, ...] */ if (bson_iter_init_find (&iter, reply, "upserted")) { if (BSON_ITER_HOLDS_ARRAY (&iter) && (bson_iter_recurse (&iter, &ar))) { while (bson_iter_next (&ar)) { if (BSON_ITER_HOLDS_DOCUMENT (&ar) && bson_iter_recurse (&ar, &citer) && bson_iter_find (&citer, "index") && BSON_ITER_HOLDS_INT32 (&citer)) { server_index = bson_iter_int32 (&citer); if (bson_iter_recurse (&ar, &citer) && bson_iter_find (&citer, "_id")) { value = bson_iter_value (&citer); _mongoc_write_result_append_upsert (result, offset + server_index, value); n_upserted++; } } } } result->nUpserted += n_upserted; /* * XXX: The following addition to nMatched needs some checking. * I'm highly skeptical of it. */ result->nMatched += BSON_MAX (0, (affected - n_upserted)); } else { result->nMatched += affected; } /* * SERVER-13001 - in a mixed sharded cluster a call to update could * return nModified (>= 2.6) or not (<= 2.4). If any call does not * return nModified we can't report a valid final count so omit the * field completely. */ if (bson_iter_init_find (&iter, reply, "nModified") && BSON_ITER_HOLDS_INT32 (&iter)) { result->nModified += bson_iter_int32 (&iter); } else { /* * nModified could be BSON_TYPE_NULL, which should also be omitted. */ result->omit_nModified = true; } break; default: BSON_ASSERT (false); break; } if (bson_iter_init_find (&iter, reply, "writeErrors") && BSON_ITER_HOLDS_ARRAY (&iter)) { _mongoc_write_result_merge_arrays (offset, result, &result->writeErrors, &iter); } if (bson_iter_init_find (&iter, reply, "writeConcernError") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { uint32_t len; const uint8_t *data; bson_t write_concern_error; char str[16]; const char *key; /* writeConcernError is a subdocument in the server response * append it to the result->writeConcernErrors array */ bson_iter_document (&iter, &len, &data); bson_init_static (&write_concern_error, data, len); bson_uint32_to_string (result->n_writeConcernErrors, &key, str, sizeof str); bson_append_document (&result->writeConcernErrors, key, -1, &write_concern_error); result->n_writeConcernErrors++; } EXIT; } /* * If error is not set, set code from first document in array like * [{"code": 64, "errmsg": "duplicate"}, ...]. Format the error message * from all errors in array. */ static void _set_error_from_response (bson_t *bson_array, mongoc_error_domain_t domain, const char *error_type, bson_error_t *error /* OUT */) { bson_iter_t array_iter; bson_iter_t doc_iter; bson_string_t *compound_err; const char *errmsg = NULL; int32_t code = 0; uint32_t n_keys, i; compound_err = bson_string_new (NULL); n_keys = bson_count_keys (bson_array); if (n_keys > 1) { bson_string_append_printf (compound_err, "Multiple %s errors: ", error_type); } if (!bson_empty0 (bson_array) && bson_iter_init (&array_iter, bson_array)) { /* get first code and all error messages */ i = 0; while (bson_iter_next (&array_iter)) { if (BSON_ITER_HOLDS_DOCUMENT (&array_iter) && bson_iter_recurse (&array_iter, &doc_iter)) { /* parse doc, which is like {"code": 64, "errmsg": "duplicate"} */ while (bson_iter_next (&doc_iter)) { /* use the first error code we find */ if (BSON_ITER_IS_KEY (&doc_iter, "code") && code == 0) { code = bson_iter_int32 (&doc_iter); } else if (BSON_ITER_IS_KEY (&doc_iter, "errmsg")) { errmsg = bson_iter_utf8 (&doc_iter, NULL); /* build message like 'Multiple write errors: "foo", "bar"' */ if (n_keys > 1) { bson_string_append_printf (compound_err, "\"%s\"", errmsg); if (i < n_keys - 1) { bson_string_append (compound_err, ", "); } } else { /* single error message */ bson_string_append (compound_err, errmsg); } } } i++; } } if (code && compound_err->len) { bson_set_error (error, domain, (uint32_t) code, "%s", compound_err->str); } } bson_string_free (compound_err, true); } bool _mongoc_write_result_complete (mongoc_write_result_t *result, bson_t *bson, bson_error_t *error) { ENTRY; BSON_ASSERT (result); if (bson) { BSON_APPEND_INT32 (bson, "nInserted", result->nInserted); BSON_APPEND_INT32 (bson, "nMatched", result->nMatched); if (!result->omit_nModified) { BSON_APPEND_INT32 (bson, "nModified", result->nModified); } BSON_APPEND_INT32 (bson, "nRemoved", result->nRemoved); BSON_APPEND_INT32 (bson, "nUpserted", result->nUpserted); if (!bson_empty0 (&result->upserted)) { BSON_APPEND_ARRAY (bson, "upserted", &result->upserted); } BSON_APPEND_ARRAY (bson, "writeErrors", &result->writeErrors); if (result->n_writeConcernErrors) { BSON_APPEND_ARRAY (bson, "writeConcernErrors", &result->writeConcernErrors); } } /* set bson_error_t from first write error or write concern error */ _set_error_from_response (&result->writeErrors, MONGOC_ERROR_COMMAND, "write", &result->error); if (!result->error.code) { _set_error_from_response (&result->writeConcernErrors, MONGOC_ERROR_WRITE_CONCERN, "write concern", &result->error); } if (error) { memcpy (error, &result->error, sizeof *error); } RETURN (!result->failed && result->error.code == 0); } libmongoc-1.3.1/src/mongoc/mongoc-write-concern-private.h000066400000000000000000000030601264720626300234250ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_WRITE_CONCERN_PRIVATE_H #define MONGOC_WRITE_CONCERN_PRIVATE_H #if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION) #error "Only can be included directly." #endif #include BSON_BEGIN_DECLS #define MONGOC_WRITE_CONCERN_FSYNC_DEFAULT -1 #define MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT -1 struct _mongoc_write_concern_t { int8_t fsync_; int8_t journal; int32_t w; int32_t wtimeout; char *wtag; bool frozen; bson_t compiled; bson_t compiled_gle; }; const bson_t *_mongoc_write_concern_get_gle (mongoc_write_concern_t *write_concern); const bson_t *_mongoc_write_concern_get_bson (mongoc_write_concern_t *write_concern); bool _mongoc_write_concern_needs_gle (const mongoc_write_concern_t *write_concern); bool _mongoc_write_concern_is_valid (const mongoc_write_concern_t *write_concern); BSON_END_DECLS #endif /* MONGOC_WRITE_CONCERN_PRIVATE_H */ libmongoc-1.3.1/src/mongoc/mongoc-write-concern.c000066400000000000000000000271301264720626300217540ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-log.h" #include "mongoc-write-concern.h" #include "mongoc-write-concern-private.h" static BSON_INLINE bool _mongoc_write_concern_warn_frozen (mongoc_write_concern_t *write_concern) { if (write_concern->frozen) { MONGOC_WARNING("Cannot modify a frozen write-concern."); } return write_concern->frozen; } static void _mongoc_write_concern_freeze (mongoc_write_concern_t *write_concern); /** * mongoc_write_concern_new: * * Create a new mongoc_write_concern_t. * * Returns: A newly allocated mongoc_write_concern_t. This should be freed * with mongoc_write_concern_destroy(). */ mongoc_write_concern_t * mongoc_write_concern_new (void) { mongoc_write_concern_t *write_concern; write_concern = (mongoc_write_concern_t *)bson_malloc0(sizeof *write_concern); write_concern->w = MONGOC_WRITE_CONCERN_W_DEFAULT; write_concern->fsync_ = MONGOC_WRITE_CONCERN_FSYNC_DEFAULT; write_concern->journal = MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT; return write_concern; } mongoc_write_concern_t * mongoc_write_concern_copy (const mongoc_write_concern_t *write_concern) { mongoc_write_concern_t *ret = NULL; if (write_concern) { ret = mongoc_write_concern_new(); ret->fsync_ = write_concern->fsync_; ret->journal = write_concern->journal; ret->w = write_concern->w; ret->wtimeout = write_concern->wtimeout; ret->frozen = false; ret->wtag = bson_strdup (write_concern->wtag); } return ret; } /** * mongoc_write_concern_destroy: * @write_concern: A mongoc_write_concern_t. * * Releases a mongoc_write_concern_t and all associated memory. */ void mongoc_write_concern_destroy (mongoc_write_concern_t *write_concern) { if (write_concern) { if (write_concern->compiled.len) { bson_destroy (&write_concern->compiled); bson_destroy (&write_concern->compiled_gle); } bson_free (write_concern->wtag); bson_free (write_concern); } } bool mongoc_write_concern_get_fsync (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return (write_concern->fsync_ == true); } /** * mongoc_write_concern_set_fsync: * @write_concern: A mongoc_write_concern_t. * @fsync_: If the write concern requires fsync() by the server. * * Set if fsync() should be called on the server before acknowledging a * write request. */ void mongoc_write_concern_set_fsync (mongoc_write_concern_t *write_concern, bool fsync_) { BSON_ASSERT (write_concern); if (!_mongoc_write_concern_warn_frozen(write_concern)) { write_concern->fsync_ = !!fsync_; } } bool mongoc_write_concern_get_journal (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return (write_concern->journal == true); } /** * mongoc_write_concern_set_journal: * @write_concern: A mongoc_write_concern_t. * @journal: If the write should be journaled. * * Set if the write request should be journaled before acknowledging the * write request. */ void mongoc_write_concern_set_journal (mongoc_write_concern_t *write_concern, bool journal) { BSON_ASSERT (write_concern); if (!_mongoc_write_concern_warn_frozen(write_concern)) { write_concern->journal = !!journal; } } int32_t mongoc_write_concern_get_w (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return write_concern->w; } /** * mongoc_write_concern_set_w: * @w: The number of nodes for write or MONGOC_WRITE_CONCERN_W_MAJORITY * for "majority". * * Sets the number of nodes that must acknowledge the write request before * acknowledging the write request to the client. * * You may specifiy @w as MONGOC_WRITE_CONCERN_W_MAJORITY to request that * a "majority" of nodes acknowledge the request. */ void mongoc_write_concern_set_w (mongoc_write_concern_t *write_concern, int32_t w) { BSON_ASSERT (write_concern); BSON_ASSERT (w >= -3); if (!_mongoc_write_concern_warn_frozen(write_concern)) { write_concern->w = w; } } int32_t mongoc_write_concern_get_wtimeout (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return write_concern->wtimeout; } /** * mongoc_write_concern_set_wtimeout: * @write_concern: A mongoc_write_concern_t. * @wtimeout_msec: Number of milliseconds before timeout. * * Sets the number of milliseconds to wait before considering a write * request as failed. A value of 0 indicates no write timeout. * * The @wtimeout_msec parameter must be positive or zero. Negative values will * be ignored. */ void mongoc_write_concern_set_wtimeout (mongoc_write_concern_t *write_concern, int32_t wtimeout_msec) { BSON_ASSERT (write_concern); if (wtimeout_msec < 0) { return; } if (!_mongoc_write_concern_warn_frozen(write_concern)) { write_concern->wtimeout = wtimeout_msec; } } bool mongoc_write_concern_get_wmajority (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return (write_concern->w == MONGOC_WRITE_CONCERN_W_MAJORITY); } /** * mongoc_write_concern_set_wmajority: * @write_concern: A mongoc_write_concern_t. * @wtimeout_msec: Number of milliseconds before timeout. * * Sets the "w" of a write concern to "majority". It is suggested that * you provide a reasonable @wtimeout_msec to wait before considering the * write request failed. A @wtimeout_msec value of 0 indicates no write timeout. * * The @wtimeout_msec parameter must be positive or zero. Negative values will * be ignored. */ void mongoc_write_concern_set_wmajority (mongoc_write_concern_t *write_concern, int32_t wtimeout_msec) { BSON_ASSERT (write_concern); if (!_mongoc_write_concern_warn_frozen(write_concern)) { write_concern->w = MONGOC_WRITE_CONCERN_W_MAJORITY; if (wtimeout_msec >= 0) { write_concern->wtimeout = wtimeout_msec; } } } const char * mongoc_write_concern_get_wtag (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); if (write_concern->w == MONGOC_WRITE_CONCERN_W_TAG) { return write_concern->wtag; } return NULL; } void mongoc_write_concern_set_wtag (mongoc_write_concern_t *write_concern, const char *wtag) { BSON_ASSERT (write_concern); if (!_mongoc_write_concern_warn_frozen (write_concern)) { bson_free (write_concern->wtag); write_concern->wtag = bson_strdup (wtag); write_concern->w = MONGOC_WRITE_CONCERN_W_TAG; } } /** * mongoc_write_concern_get_bson: * @write_concern: A mongoc_write_concern_t. * * This is an internal function. * * Freeze the write concern if necessary and retrieve the encoded bson_t * representing the write concern. * * You may not modify the write concern further after calling this function. * * Returns: A bson_t that should not be modified or freed as it is owned by * the mongoc_write_concern_t instance. */ const bson_t * _mongoc_write_concern_get_bson (mongoc_write_concern_t *write_concern) { if (!write_concern->frozen) { _mongoc_write_concern_freeze(write_concern); } return &write_concern->compiled; } /** * mongoc_write_concern_get_gle: * @write_concern: A mongoc_write_concern_t. * * This is an internal function. * * Freeze the write concern if necessary and retrieve the encoded bson_t * representing the write concern as a get last error command. * * You may not modify the write concern further after calling this function. * * Returns: A bson_t that should not be modified or freed as it is owned by * the mongoc_write_concern_t instance. */ const bson_t * _mongoc_write_concern_get_gle (mongoc_write_concern_t *write_concern) { if (!write_concern->frozen) { _mongoc_write_concern_freeze(write_concern); } return &write_concern->compiled_gle; } /** * mongoc_write_concern_freeze: * @write_concern: A mongoc_write_concern_t. * * This is an internal function. * * Freeze the write concern if necessary and encode it into a bson_ts which * represent the raw bson form and the get last error command form. * * You may not modify the write concern further after calling this function. */ static void _mongoc_write_concern_freeze (mongoc_write_concern_t *write_concern) { bson_t *compiled; bson_t *compiled_gle; BSON_ASSERT (write_concern); compiled = &write_concern->compiled; compiled_gle = &write_concern->compiled_gle; write_concern->frozen = true; bson_init (compiled); bson_init (compiled_gle); if (write_concern->w == MONGOC_WRITE_CONCERN_W_TAG) { BSON_ASSERT (write_concern->wtag); BSON_APPEND_UTF8 (compiled, "w", write_concern->wtag); } else if (write_concern->w == MONGOC_WRITE_CONCERN_W_MAJORITY) { BSON_APPEND_UTF8 (compiled, "w", "majority"); } else if (write_concern->w == MONGOC_WRITE_CONCERN_W_DEFAULT) { /* Do Nothing */ } else if (write_concern->w > 0) { BSON_APPEND_INT32 (compiled, "w", write_concern->w); } if (write_concern->fsync_ != MONGOC_WRITE_CONCERN_FSYNC_DEFAULT) { bson_append_bool(compiled, "fsync", 5, !!write_concern->fsync_); } if (write_concern->journal != MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT) { bson_append_bool(compiled, "j", 1, !!write_concern->journal); } if (write_concern->wtimeout) { bson_append_int32(compiled, "wtimeout", 8, write_concern->wtimeout); } BSON_APPEND_INT32 (compiled_gle, "getlasterror", 1); bson_concat (compiled_gle, compiled); } /** * mongoc_write_concern_needs_gle: * @concern: (in): A mongoc_write_concern_t. * * Checks to see if @write_concern requests that a getlasterror command is to * be delivered to the MongoDB server. * * Returns: true if a getlasterror command should be sent. */ bool _mongoc_write_concern_needs_gle (const mongoc_write_concern_t *write_concern) { if (write_concern) { return (((write_concern->w != MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED) && (write_concern->w != MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED)) || mongoc_write_concern_get_fsync(write_concern) || mongoc_write_concern_get_journal(write_concern)); } return false; } /** * _mongoc_write_concern_is_valid: * @write_concern: (in): A mongoc_write_concern_t. * * Checks to see if @write_concern is valid and does not contain conflicting * options. * * Returns: true if the write concern is valid; otherwise false. */ bool _mongoc_write_concern_is_valid (const mongoc_write_concern_t *write_concern) { if (!write_concern) { return false; } /* Journal or fsync should require acknowledgement. */ if ((mongoc_write_concern_get_fsync (write_concern) || mongoc_write_concern_get_journal (write_concern)) && (write_concern->w == MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED || write_concern->w == MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED)) { return false; } if (write_concern->wtimeout < 0) { return false; } return true; } libmongoc-1.3.1/src/mongoc/mongoc-write-concern.h000066400000000000000000000064271264720626300217670ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_WRITE_CONCERN_H #define MONGOC_WRITE_CONCERN_H #if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) # error "Only can be included directly." #endif #include BSON_BEGIN_DECLS #define MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED 0 #define MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED -1 /* deprecated */ #define MONGOC_WRITE_CONCERN_W_DEFAULT -2 #define MONGOC_WRITE_CONCERN_W_MAJORITY -3 #define MONGOC_WRITE_CONCERN_W_TAG -4 typedef struct _mongoc_write_concern_t mongoc_write_concern_t; mongoc_write_concern_t *mongoc_write_concern_new (void); mongoc_write_concern_t *mongoc_write_concern_copy (const mongoc_write_concern_t *write_concern); void mongoc_write_concern_destroy (mongoc_write_concern_t *write_concern); bool mongoc_write_concern_get_fsync (const mongoc_write_concern_t *write_concern); void mongoc_write_concern_set_fsync (mongoc_write_concern_t *write_concern, bool fsync_); bool mongoc_write_concern_get_journal (const mongoc_write_concern_t *write_concern); void mongoc_write_concern_set_journal (mongoc_write_concern_t *write_concern, bool journal); int32_t mongoc_write_concern_get_w (const mongoc_write_concern_t *write_concern); void mongoc_write_concern_set_w (mongoc_write_concern_t *write_concern, int32_t w); const char *mongoc_write_concern_get_wtag (const mongoc_write_concern_t *write_concern); void mongoc_write_concern_set_wtag (mongoc_write_concern_t *write_concern, const char *tag); int32_t mongoc_write_concern_get_wtimeout (const mongoc_write_concern_t *write_concern); void mongoc_write_concern_set_wtimeout (mongoc_write_concern_t *write_concern, int32_t wtimeout_msec); bool mongoc_write_concern_get_wmajority (const mongoc_write_concern_t *write_concern); void mongoc_write_concern_set_wmajority (mongoc_write_concern_t *write_concern, int32_t wtimeout_msec); BSON_END_DECLS #endif /* MONGOC_WRITE_CONCERN_H */ libmongoc-1.3.1/src/mongoc/mongoc.h000066400000000000000000000032421264720626300172020ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_H #define MONGOC_H #include #define MONGOC_INSIDE #include "mongoc-bulk-operation.h" #include "mongoc-client.h" #include "mongoc-client-pool.h" #include "mongoc-collection.h" #include "mongoc-config.h" #include "mongoc-cursor.h" #include "mongoc-database.h" #include "mongoc-index.h" #include "mongoc-error.h" #include "mongoc-flags.h" #include "mongoc-gridfs.h" #include "mongoc-gridfs-file.h" #include "mongoc-gridfs-file-list.h" #include "mongoc-gridfs-file-page.h" #include "mongoc-host-list.h" #include "mongoc-init.h" #include "mongoc-matcher.h" #include "mongoc-opcode.h" #include "mongoc-log.h" #include "mongoc-socket.h" #include "mongoc-stream.h" #include "mongoc-stream-buffered.h" #include "mongoc-stream-file.h" #include "mongoc-stream-gridfs.h" #include "mongoc-stream-socket.h" #include "mongoc-uri.h" #include "mongoc-write-concern.h" #include "mongoc-version.h" #include "mongoc-version-functions.h" #ifdef MONGOC_ENABLE_SSL #include "mongoc-rand.h" #include "mongoc-stream-tls.h" #include "mongoc-ssl.h" #endif #undef MONGOC_INSIDE #endif /* MONGOC_H */ libmongoc-1.3.1/src/mongoc/op-delete.def000066400000000000000000000003161264720626300201040ustar00rootroot00000000000000RPC( delete, INT32_FIELD(msg_len) INT32_FIELD(request_id) INT32_FIELD(response_to) INT32_FIELD(opcode) INT32_FIELD(zero) CSTRING_FIELD(collection) ENUM_FIELD(flags) BSON_FIELD(selector) ) libmongoc-1.3.1/src/mongoc/op-get-more.def000066400000000000000000000003261264720626300203620ustar00rootroot00000000000000RPC( get_more, INT32_FIELD(msg_len) INT32_FIELD(request_id) INT32_FIELD(response_to) INT32_FIELD(opcode) INT32_FIELD(zero) CSTRING_FIELD(collection) INT32_FIELD(n_return) INT64_FIELD(cursor_id) ) libmongoc-1.3.1/src/mongoc/op-header.def000066400000000000000000000001631264720626300200720ustar00rootroot00000000000000RPC( header, INT32_FIELD(msg_len) INT32_FIELD(request_id) INT32_FIELD(response_to) INT32_FIELD(opcode) ) libmongoc-1.3.1/src/mongoc/op-insert.def000066400000000000000000000003021264720626300201410ustar00rootroot00000000000000RPC( insert, INT32_FIELD(msg_len) INT32_FIELD(request_id) INT32_FIELD(response_to) INT32_FIELD(opcode) ENUM_FIELD(flags) CSTRING_FIELD(collection) IOVEC_ARRAY_FIELD(documents) ) libmongoc-1.3.1/src/mongoc/op-kill-cursors.def000066400000000000000000000002651264720626300212760ustar00rootroot00000000000000RPC( kill_cursors, INT32_FIELD(msg_len) INT32_FIELD(request_id) INT32_FIELD(response_to) INT32_FIELD(opcode) INT32_FIELD(zero) INT64_ARRAY_FIELD(n_cursors, cursors) ) libmongoc-1.3.1/src/mongoc/op-msg.def000066400000000000000000000002051264720626300174250ustar00rootroot00000000000000RPC( msg, INT32_FIELD(msg_len) INT32_FIELD(request_id) INT32_FIELD(response_to) INT32_FIELD(opcode) CSTRING_FIELD(msg) ) libmongoc-1.3.1/src/mongoc/op-query.def000066400000000000000000000004161264720626300200100ustar00rootroot00000000000000RPC( query, INT32_FIELD(msg_len) INT32_FIELD(request_id) INT32_FIELD(response_to) INT32_FIELD(opcode) ENUM_FIELD(flags) CSTRING_FIELD(collection) INT32_FIELD(skip) INT32_FIELD(n_return) BSON_FIELD(query) BSON_OPTIONAL(fields, BSON_FIELD(fields)) ) libmongoc-1.3.1/src/mongoc/op-reply.def000066400000000000000000000003611264720626300177750ustar00rootroot00000000000000RPC( reply, INT32_FIELD(msg_len) INT32_FIELD(request_id) INT32_FIELD(response_to) INT32_FIELD(opcode) ENUM_FIELD(flags) INT64_FIELD(cursor_id) INT32_FIELD(start_from) INT32_FIELD(n_returned) BSON_ARRAY_FIELD(documents) ) libmongoc-1.3.1/src/mongoc/op-update.def000066400000000000000000000003431264720626300201240ustar00rootroot00000000000000RPC( update, INT32_FIELD(msg_len) INT32_FIELD(request_id) INT32_FIELD(response_to) INT32_FIELD(opcode) INT32_FIELD(zero) CSTRING_FIELD(collection) ENUM_FIELD(flags) BSON_FIELD(selector) BSON_FIELD(update) ) libmongoc-1.3.1/src/mongoc/uncrustify.cfg000066400000000000000000000067711264720626300204550ustar00rootroot00000000000000align_struct_init_span = 1 align_var_def_colon = true align_var_def_span = 0 indent_align_string = true indent_brace = 0 mod_paren_on_return = remove nl_func_var_def_blk = 1 align_enum_equ_span = 3 align_enum_equ_thresh = 0 align_func_params = true align_typedef_star_style = 2 align_var_def_inline = true align_var_def_star_style = 2 align_var_struct_span = 1 align_with_tabs = false cmt_star_cont = true code_width = 80 eat_blanks_after_open_brace = true eat_blanks_before_close_brace = true output_tab_size = 3 indent_case_brace = output_tab_size indent_columns = output_tab_size indent_switch_case = 0 indent_func_call_param = false indent_func_def_param = false indent_func_proto_param = false indent_label = -3 indent_with_tabs = 0 input_tab_size = 3 mod_full_brace_do = add mod_full_brace_for = add mod_full_brace_if = add mod_full_brace_while = add mod_remove_extra_semicolon = true nl_after_if = add nl_assign_leave_one_liners = true nl_before_if = add nl_before_for = add nl_brace_else = remove nl_brace_while = remove nl_do_brace = remove nl_else_brace = remove nl_enum_brace = add nl_fcall_brace = add nl_fdef_brace = add nl_for_brace = remove nl_func_decl_args = add nl_func_decl_end = remove nl_func_def_args = add nl_func_def_end = remove nl_func_paren = remove nl_func_proto_type_name = add nl_func_type_name = force nl_if_brace = remove nl_if_leave_one_liners = true nl_squeeze_ifdef = false nl_struct_brace = add nl_switch_brace = remove nl_union_brace = remove nl_while_brace = remove sp_after_cast = remove sp_after_comma = force sp_after_ptr_star = remove sp_after_sparen = force sp_arith = force sp_assign = force sp_attribute_paren = remove sp_before_comma = remove sp_before_ptr_star = add sp_before_semi = remove sp_before_sparen = force sp_between_ptr_star = remove sp_bool = force sp_compare = force sp_enum_assign = add sp_func_call_paren = add sp_func_def_paren = add sp_func_proto_paren = force sp_inside_braces = force sp_inside_braces_enum = force sp_inside_braces_struct = force sp_inside_fparen = remove sp_inside_paren = remove sp_inside_sparen = remove sp_inside_tparen = remove sp_macro = add sp_macro_func = add sp_paren_paren = remove sp_pp_concat = remove sp_return_paren = force sp_sizeof_paren = force libmongoc-1.3.1/src/mongoc/utlist.h000066400000000000000000001551121264720626300172500ustar00rootroot00000000000000/* Copyright (c) 2007-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ 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. 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 UTLIST_H #define UTLIST_H #define UTLIST_VERSION 1.9.9 #include /* * This file contains macros to manipulate singly and doubly-linked lists. * * 1. LL_ macros: singly-linked lists. * 2. DL_ macros: doubly-linked lists. * 3. CDL_ macros: circular doubly-linked lists. * * To use singly-linked lists, your structure must have a "next" pointer. * To use doubly-linked lists, your structure must "prev" and "next" pointers. * Either way, the pointer to the head of the list must be initialized to NULL. * * ----------------.EXAMPLE ------------------------- * struct item { * int id; * struct item *prev, *next; * } * * struct item *list = NULL: * * int main() { * struct item *item; * ... allocate and populate item ... * DL_APPEND(list, item); * } * -------------------------------------------------- * * For doubly-linked lists, the append and delete macros are O(1) * For singly-linked lists, append and delete are O(n) but prepend is O(1) * The sort macro is O(n log(n)) for all types of single/double/circular lists. */ /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ code), this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #ifdef _MSC_VER /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define LDECLTYPE(x) decltype(x) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #define LDECLTYPE(x) char* #endif #elif defined(__ICCARM__) #define NO_DECLTYPE #define LDECLTYPE(x) char* #else /* GNU, Sun and other compilers */ #define LDECLTYPE(x) __typeof(x) #endif /* for VS2008 we use some workarounds to get around the lack of decltype, * namely, we always reassign our tmp variable to the list head if we need * to dereference its prev/next pointers, and save/restore the real head.*/ #ifdef NO_DECLTYPE #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } #define _NEXT(elt,list,next) ((char*)((list)->next)) #define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } /* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ #define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } #else #define _SV(elt,list) #define _NEXT(elt,list,next) ((elt)->next) #define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) /* #define _PREV(elt,list,prev) ((elt)->prev) */ #define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) #define _RS(list) #define _CASTASGN(a,b) (a)=(b) #endif /****************************************************************************** * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * * Unwieldy variable names used here to avoid shadowing passed-in variables. * *****************************************************************************/ #define LL_SORT(list, cmp) \ LL_SORT2(list, cmp, next) #define LL_SORT2(list, cmp, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ list = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ } \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define DL_SORT(list, cmp) \ DL_SORT2(list, cmp, prev, next) #define DL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ list = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ _CASTASGN(list->prev, _ls_tail); \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define CDL_SORT(list, cmp) \ CDL_SORT2(list, cmp, prev, next) #define CDL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ LDECLTYPE(list) _ls_oldhead; \ LDECLTYPE(list) _tmp; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ _CASTASGN(_ls_oldhead,list); \ list = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); \ if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ _ls_q = NULL; \ } else { \ _ls_q = _NEXT(_ls_q,list,next); \ } \ _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ _CASTASGN(list->prev,_ls_tail); \ _CASTASGN(_tmp,list); \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) /****************************************************************************** * singly linked list macros (non-circular) * *****************************************************************************/ #define LL_PREPEND(head,add) \ LL_PREPEND2(head,add,next) #define LL_PREPEND2(head,add,next) \ do { \ (add)->next = head; \ head = add; \ } while (0) #define LL_CONCAT(head1,head2) \ LL_CONCAT2(head1,head2,next) #define LL_CONCAT2(head1,head2,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head1) { \ _tmp = head1; \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(head2); \ } else { \ (head1)=(head2); \ } \ } while (0) #define LL_APPEND(head,add) \ LL_APPEND2(head,add,next) #define LL_APPEND2(head,add,next) \ do { \ LDECLTYPE(head) _tmp; \ (add)->next=NULL; \ if (head) { \ _tmp = head; \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(add); \ } else { \ (head)=(add); \ } \ } while (0) #define LL_DELETE(head,del) \ LL_DELETE2(head,del,next) #define LL_DELETE2(head,del,next) \ do { \ LDECLTYPE(head) _tmp; \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ _tmp = head; \ while (_tmp->next && (_tmp->next != (del))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = ((del)->next); \ } \ } \ } while (0) /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ #define LL_APPEND_VS2008(head,add) \ LL_APPEND2_VS2008(head,add,next) #define LL_APPEND2_VS2008(head,add,next) \ do { \ if (head) { \ (add)->next = head; /* use add->next as a temp variable */ \ while ((add)->next->next) { (add)->next = (add)->next->next; } \ (add)->next->next=(add); \ } else { \ (head)=(add); \ } \ (add)->next=NULL; \ } while (0) #define LL_DELETE_VS2008(head,del) \ LL_DELETE2_VS2008(head,del,next) #define LL_DELETE2_VS2008(head,del,next) \ do { \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ char *_tmp = (char*)(head); \ while ((head)->next && ((head)->next != (del))) { \ head = (head)->next; \ } \ if ((head)->next) { \ (head)->next = ((del)->next); \ } \ { \ char **_head_alias = (char**)&(head); \ *_head_alias = _tmp; \ } \ } \ } while (0) #ifdef NO_DECLTYPE #undef LL_APPEND #define LL_APPEND LL_APPEND_VS2008 #undef LL_DELETE #define LL_DELETE LL_DELETE_VS2008 #undef LL_DELETE2 #define LL_DELETE2 LL_DELETE2_VS2008 #undef LL_APPEND2 #define LL_APPEND2 LL_APPEND2_VS2008 #undef LL_CONCAT /* no LL_CONCAT_VS2008 */ #undef DL_CONCAT /* no DL_CONCAT_VS2008 */ #endif /* end VS2008 replacements */ #define LL_COUNT(head,el,counter) \ LL_COUNT2(head,el,counter,next) \ #define LL_COUNT2(head,el,counter,next) \ { \ counter = 0; \ LL_FOREACH2(head,el,next){ ++counter; } \ } #define LL_FOREACH(head,el) \ LL_FOREACH2(head,el,next) #define LL_FOREACH2(head,el,next) \ for(el=head;el;el=(el)->next) #define LL_FOREACH_SAFE(head,el,tmp) \ LL_FOREACH_SAFE2(head,el,tmp,next) #define LL_FOREACH_SAFE2(head,el,tmp,next) \ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) #define LL_SEARCH_SCALAR(head,out,field,val) \ LL_SEARCH_SCALAR2(head,out,field,val,next) #define LL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while(0) #define LL_SEARCH(head,out,elt,cmp) \ LL_SEARCH2(head,out,elt,cmp,next) #define LL_SEARCH2(head,out,elt,cmp,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while(0) #define LL_REPLACE_ELEM(head, el, add) \ do { \ LDECLTYPE(head) _tmp; \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el)->next; \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = head; \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } while (0) #define LL_PREPEND_ELEM(head, el, add) \ do { \ LDECLTYPE(head) _tmp; \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = head; \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } while (0) \ /****************************************************************************** * doubly linked list macros (non-circular) * *****************************************************************************/ #define DL_PREPEND(head,add) \ DL_PREPEND2(head,add,prev,next) #define DL_PREPEND2(head,add,prev,next) \ do { \ (add)->next = head; \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev = (add); \ } else { \ (add)->prev = (add); \ } \ (head) = (add); \ } while (0) #define DL_APPEND(head,add) \ DL_APPEND2(head,add,prev,next) #define DL_APPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev->next = (add); \ (head)->prev = (add); \ (add)->next = NULL; \ } else { \ (head)=(add); \ (head)->prev = (head); \ (head)->next = NULL; \ } \ } while (0) #define DL_CONCAT(head1,head2) \ DL_CONCAT2(head1,head2,prev,next) #define DL_CONCAT2(head1,head2,prev,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head2) { \ if (head1) { \ _tmp = (head2)->prev; \ (head2)->prev = (head1)->prev; \ (head1)->prev->next = (head2); \ (head1)->prev = _tmp; \ } else { \ (head1)=(head2); \ } \ } \ } while (0) #define DL_DELETE(head,del) \ DL_DELETE2(head,del,prev,next) #define DL_DELETE2(head,del,prev,next) \ do { \ assert((del)->prev != NULL); \ if ((del)->prev == (del)) { \ (head)=NULL; \ } else if ((del)==(head)) { \ (del)->next->prev = (del)->prev; \ (head) = (del)->next; \ } else { \ (del)->prev->next = (del)->next; \ if ((del)->next) { \ (del)->next->prev = (del)->prev; \ } else { \ (head)->prev = (del)->prev; \ } \ } \ } while (0) #define DL_COUNT(head,el,counter) \ DL_COUNT2(head,el,counter,next) \ #define DL_COUNT2(head,el,counter,next) \ { \ counter = 0; \ DL_FOREACH2(head,el,next){ ++counter; } \ } #define DL_FOREACH(head,el) \ DL_FOREACH2(head,el,next) #define DL_FOREACH2(head,el,next) \ for(el=head;el;el=(el)->next) /* this version is safe for deleting the elements during iteration */ #define DL_FOREACH_SAFE(head,el,tmp) \ DL_FOREACH_SAFE2(head,el,tmp,next) #define DL_FOREACH_SAFE2(head,el,tmp,next) \ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) /* these are identical to their singly-linked list counterparts */ #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR #define DL_SEARCH LL_SEARCH #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 #define DL_SEARCH2 LL_SEARCH2 #define DL_REPLACE_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ if ((head) == (el)) { \ (head) = (add); \ (add)->next = (el)->next; \ if ((el)->next == NULL) { \ (add)->prev = (add); \ } else { \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ } \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->prev->next = (add); \ if ((el)->next == NULL) { \ (head)->prev = (add); \ } else { \ (add)->next->prev = (add); \ } \ } \ } while (0) #define DL_PREPEND_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ (add)->prev->next = (add); \ } \ } while (0) \ /****************************************************************************** * circular doubly linked list macros * *****************************************************************************/ #define CDL_PREPEND(head,add) \ CDL_PREPEND2(head,add,prev,next) #define CDL_PREPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (add)->next = (head); \ (head)->prev = (add); \ (add)->prev->next = (add); \ } else { \ (add)->prev = (add); \ (add)->next = (add); \ } \ (head)=(add); \ } while (0) #define CDL_DELETE(head,del) \ CDL_DELETE2(head,del,prev,next) #define CDL_DELETE2(head,del,prev,next) \ do { \ if ( ((head)==(del)) && ((head)->next == (head))) { \ (head) = 0L; \ } else { \ (del)->next->prev = (del)->prev; \ (del)->prev->next = (del)->next; \ if ((del) == (head)) (head)=(del)->next; \ } \ } while (0) #define CDL_COUNT(head,el,counter) \ CDL_COUNT2(head,el,counter,next) \ #define CDL_COUNT2(head, el, counter,next) \ { \ counter = 0; \ CDL_FOREACH2(head,el,next){ ++counter; } \ } #define CDL_FOREACH(head,el) \ CDL_FOREACH2(head,el,next) #define CDL_FOREACH2(head,el,next) \ for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ (el) && ((tmp2)=(el)->next, 1); \ ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) #define CDL_SEARCH_SCALAR(head,out,field,val) \ CDL_SEARCH_SCALAR2(head,out,field,val,next) #define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while(0) #define CDL_SEARCH(head,out,elt,cmp) \ CDL_SEARCH2(head,out,elt,cmp,next) #define CDL_SEARCH2(head,out,elt,cmp,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while(0) #define CDL_REPLACE_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ if ((el)->next == (el)) { \ (add)->next = (add); \ (add)->prev = (add); \ (head) = (add); \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } \ } while (0) #define CDL_PREPEND_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } while (0) \ #endif /* UTLIST_H */ libmongoc-1.3.1/src/tools/000077500000000000000000000000001264720626300154245ustar00rootroot00000000000000libmongoc-1.3.1/src/tools/Makefile.am000066400000000000000000000005201264720626300174550ustar00rootroot00000000000000bin_PROGRAMS += mongoc-stat mongoc_stat_SOURCES = src/tools/mongoc-stat.c mongoc_stat_CFLAGS = \ $(LIBC_FEATURES) \ $(OPTIMIZE_CFLAGS) \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/mongoc \ -I$(top_builddir)/src/mongoc \ $(BSON_CFLAGS) mongoc_stat_LDFLAGS = \ $(OPTIMIZE_LDFLAGS) mongoc_stat_LDADD = \ $(BSON_LIBS) \ $(SHM_LIB) libmongoc-1.3.1/src/tools/mongoc-stat.c000066400000000000000000000117121264720626300200250ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #ifdef BSON_OS_UNIX #include #include #include #include #include #include #pragma pack(1) typedef struct { uint32_t offset; uint32_t slot; char category[24]; char name[32]; char description[64]; } mongoc_counter_info_t; #pragma pack() BSON_STATIC_ASSERT(sizeof(mongoc_counter_info_t) == 128); #pragma pack(1) typedef struct { uint32_t size; uint32_t n_cpu; uint32_t n_counters; uint32_t infos_offset; uint32_t values_offset; uint8_t padding[44]; } mongoc_counters_t; #pragma pack() BSON_STATIC_ASSERT(sizeof(mongoc_counters_t) == 64); typedef struct { int64_t slots[8]; } mongoc_counter_slots_t; BSON_STATIC_ASSERT(sizeof(mongoc_counter_slots_t) == 64); typedef struct { mongoc_counter_slots_t *cpus; } mongoc_counter_t; static mongoc_counters_t * mongoc_counters_new_from_pid (unsigned pid) { mongoc_counters_t *counters; int32_t len; size_t size; void *mem; char name[32]; int fd; snprintf (name, sizeof name, "/mongoc-%u", pid); name [sizeof name-1] = '\0'; if (-1 == (fd = shm_open(name, O_RDONLY, 0))) { perror("Failed to load shared memory segment"); return NULL; } if (4 != pread (fd, &len, 4, 0)) { perror("Failed to load shared memory segment"); return NULL; } if (!len) { perror("Shared memory area is not yet initialized by owning process."); return NULL; } size = len; if (MAP_FAILED == (mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0))) { fprintf(stderr, "Failed to mmap shared memory segment of size: %u", (unsigned)size); close(fd); return NULL; } counters = (mongoc_counters_t *)mem; if (counters->size != len) { perror("Corrupted shared memory segment."); return NULL; } close(fd); return counters; } static void mongoc_counters_destroy (mongoc_counters_t *counters) { BSON_ASSERT(counters); munmap((void *)counters, counters->size); } static mongoc_counter_info_t * mongoc_counters_get_infos (mongoc_counters_t *counters, uint32_t *n_infos) { mongoc_counter_info_t *info; char *base = (char *)counters; BSON_ASSERT(counters); BSON_ASSERT(n_infos); info = (mongoc_counter_info_t *)(base + counters->infos_offset); *n_infos = counters->n_counters; return info; } static int64_t mongoc_counters_get_value (mongoc_counters_t *counters, mongoc_counter_info_t *info, mongoc_counter_t *counter) { int64_t value = 0; unsigned i; for (i = 0; i < counters->n_cpu; i++) { value += counter->cpus[i].slots[info->slot]; } return value; } static void mongoc_counters_print_info (mongoc_counters_t *counters, mongoc_counter_info_t *info, FILE *file) { mongoc_counter_t ctr; int64_t value; BSON_ASSERT (info); BSON_ASSERT (file); BSON_ASSERT ((info->offset & 0x7) == 0); #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wcast-align" #endif ctr.cpus = (mongoc_counter_slots_t *)(((char *)counters)+ info->offset); #ifdef __clang__ #pragma clang diagnostic pop #endif value = mongoc_counters_get_value(counters, info, &ctr); fprintf(file, "%24s : %-24s : %-50s : %lld\n", info->category, info->name, info->description, (long long)value); } int main (int argc, char *argv[]) { mongoc_counter_info_t *infos; mongoc_counters_t *counters; uint32_t n_counters = 0; unsigned i; int pid; if (argc != 2) { fprintf(stderr, "usage: %s PID\n", argv[0]); return 1; } pid = strtol(argv[1], NULL, 10); if (!(counters = mongoc_counters_new_from_pid (pid))) { fprintf (stderr, "Failed to load shared memory for pid %u.\n", pid); return EXIT_FAILURE; } infos = mongoc_counters_get_infos (counters, &n_counters); for (i = 0; i < n_counters; i++) { mongoc_counters_print_info (counters, &infos[i], stdout); } mongoc_counters_destroy (counters); return EXIT_SUCCESS; } #else #include int main (int argc, char *argv[]) { fprintf (stderr, "mongoc-stat is not supported on your platform.\n"); return EXIT_FAILURE; } #endif libmongoc-1.3.1/tests/000077500000000000000000000000001264720626300146375ustar00rootroot00000000000000libmongoc-1.3.1/tests/.gitignore000066400000000000000000000000141264720626300166220ustar00rootroot00000000000000trust_dir/* libmongoc-1.3.1/tests/Makefile.am000066400000000000000000000170141264720626300166760ustar00rootroot00000000000000noinst_PROGRAMS += test-load noinst_PROGRAMS += test-secondary noinst_PROGRAMS += test-replica-set noinst_PROGRAMS += test-sharded-cluster noinst_PROGRAMS += test-libmongoc if ENABLE_SSL noinst_PROGRAMS += test-replica-set-ssl endif TEST_PROGS = test-libmongoc TEST_CFLAGS = if OS_SOLARIS TEST_CFLAGS += -D_REENTRANT endif TEST_CFLAGS += \ -Wno-deprecated-declarations \ -DMONGOC_COMPILATION \ -DBINARY_DIR="\"$(abs_srcdir)/tests/binary\"" \ $(BSON_CFLAGS) \ $(SSL_CFLAGS) \ $(SASL_CFLAGS) \ -I$(top_srcdir)/src/mongoc \ -I$(top_builddir)/src/mongoc TEST_LIBS = \ libmongoc-priv.la \ $(PTHREAD_LIBS) \ $(SHM_LIB) \ $(SASL_LIBS) \ $(SSL_LIBS) if EXPLICIT_LIBS TEST_LIBS += $(BSON_LIBS) endif if OS_WIN32 TEST_LIBS += -lshlwapi endif test_load_SOURCES = \ tests/test-load.c \ tests/mongoc-tests.c test_load_CFLAGS = $(TEST_CFLAGS) test_load_LDADD = $(TEST_LIBS) test_secondary_SOURCES = \ tests/test-secondary.c \ tests/mongoc-tests.c test_secondary_CFLAGS = $(TEST_CFLAGS) test_secondary_LDADD = $(TEST_LIBS) test_replica_set_SOURCES = \ tests/test-replica-set.c \ tests/ha-test.c \ tests/ha-test.h \ tests/mongoc-tests.c test_replica_set_CFLAGS = $(TEST_CFLAGS) test_replica_set_LDADD = $(TEST_LIBS) test_replica_set_ssl_SOURCES = \ tests/test-replica-set-ssl.c \ tests/ha-test.c \ tests/ha-test.h \ tests/mongoc-tests.c test_replica_set_ssl_CFLAGS = $(TEST_CFLAGS) test_replica_set_ssl_LDADD = $(TEST_LIBS) test_libmongoc_SOURCES = \ tests/debug-stream.c \ tests/json-test.c \ tests/json-test.h \ tests/mock_server/future.c \ tests/mock_server/future.h \ tests/mock_server/future-functions.c \ tests/mock_server/future-functions.h \ tests/mock_server/future-value.c \ tests/mock_server/future-value.h \ tests/mock_server/mock-server.c \ tests/mock_server/mock-server.h \ tests/mock_server/mock-rs.c \ tests/mock_server/mock-rs.h \ tests/mock_server/request.c \ tests/mock_server/request.h \ tests/mock_server/sync-queue.c \ tests/mock_server/sync-queue.h \ tests/test-libmongoc.c \ tests/test-bulk.c \ tests/test-conveniences.c \ tests/test-conveniences.h \ tests/test-mongoc-array.c \ tests/test-mongoc-async.c \ tests/test-mongoc-buffer.c \ tests/test-mongoc-client.c \ tests/test-mongoc-client-pool.c \ tests/test-mongoc-cluster.c \ tests/test-mongoc-collection.c \ tests/test-mongoc-collection-find.c \ tests/test-mongoc-cursor.c \ tests/test-mongoc-database.c \ tests/test-mongoc-exhaust.c \ tests/test-mongoc-find-and-modify.c \ tests/test-mongoc-gridfs.c \ tests/test-mongoc-gridfs-file-page.c \ tests/test-mongoc-log.c \ tests/test-mongoc-list.c \ tests/test-mongoc-matcher.c \ tests/test-mongoc-queue.c \ tests/test-mongoc-read-prefs.c \ tests/test-mongoc-rpc.c \ tests/test-mongoc-socket.c \ tests/test-mongoc-sdam.c \ tests/test-mongoc-server-selection.c \ tests/test-mongoc-server-selection-errors.c \ tests/test-mongoc-set.c \ tests/test-mongoc-stream.c \ tests/test-mongoc-thread.c \ tests/test-mongoc-topology-reconcile.c \ tests/test-mongoc-topology-scanner.c \ tests/test-mongoc-topology.c \ tests/test-mongoc-uri.c \ tests/test-mongoc-usleep.c \ tests/test-mongoc-version.c \ tests/test-mongoc-write-concern.c \ tests/test-libmongoc.h \ tests/test-sasl.c \ tests/test-write-commands.c \ tests/TestSuite.c \ tests/TestSuite.h if ENABLE_SSL test_libmongoc_SOURCES += \ tests/test-x509.c \ tests/test-mongoc-stream-tls.c \ tests/test-mongoc-stream-tls-error.c \ tests/ssl-test.c \ tests/ssl-test.h endif test_libmongoc_CFLAGS = $(TEST_CFLAGS) test_libmongoc_LDADD = $(TEST_LIBS) test_sharded_cluster_SOURCES = \ tests/test-sharded-cluster.c \ tests/ha-test.c \ tests/ha-test.h \ tests/mongoc-tests.c test_sharded_cluster_CFLAGS = $(TEST_CFLAGS) test_sharded_cluster_LDADD = $(TEST_LIBS) test_certs: tests/trust_dir/done tests/trust_dir/done: $(top_srcdir)/tests/make_ca.pl $(top_srcdir)/tests/trust_dir.cnf PATH=$(top_srcdir)/tests:${PATH} $(top_srcdir)/tests/make_ca.pl $(top_builddir)/tests/trust_dir $(top_srcdir)/tests/trust_dir.cnf touch $(top_builddir)/tests/trust_dir/done check: test abicheck TEST_ARGS = -f -p if ENABLE_SSL test: $(TEST_PROGS) test_certs else test: $(TEST_PROGS) endif @ for TEST_PROG in $(TEST_PROGS) ; do \ ./$$TEST_PROG $(TEST_ARGS) -F test.log; \ done valgrind: $(TEST_PROGS) $(LIBTOOL) --mode=execute valgrind --leak-check=full --suppressions=$(srcdir)/valgrind.suppressions ./test-libmongoc $(TEST_ARGS) if OS_LINUX abicheck: @ $(srcdir)/tests/abicheck.sh "$(srcdir)/src/libmongoc.symbols" else abicheck: endif # TODO: run tests that do not need to talk to a server local-check: DISTCLEANFILES += \ test.log \ tests/trust_dir/ca.db.serial \ tests/trust_dir/done \ tests/trust_dir/keys/rev.mongodb.com.pem \ tests/trust_dir/keys/mongodb.com.pem \ tests/trust_dir/keys/pass.mongodb.com.pem \ tests/trust_dir/keys/127.0.0.1.pem \ tests/trust_dir/keys/alt.mongodb.com.pem \ tests/trust_dir/ca.db.certs/01.pem \ tests/trust_dir/ca.db.certs/04.pem \ tests/trust_dir/ca.db.certs/05.pem \ tests/trust_dir/ca.db.certs/02.pem \ tests/trust_dir/ca.db.certs/03.pem \ tests/trust_dir/ca.db.index.attr \ tests/trust_dir/ca.db.index \ tests/trust_dir/build/mongodb.com.crt \ tests/trust_dir/build/127.0.0.1.req \ tests/trust_dir/build/mongodb.com.key \ tests/trust_dir/build/rev.mongodb.com.req \ tests/trust_dir/build/alt.mongodb.com.req \ tests/trust_dir/build/pass.mongodb.com.key \ tests/trust_dir/build/rev.mongodb.com.key \ tests/trust_dir/build/127.0.0.1.crt \ tests/trust_dir/build/pass.mongodb.com.req \ tests/trust_dir/build/rev.mongodb.com.crt \ tests/trust_dir/build/pass.mongodb.com.crt \ tests/trust_dir/build/mongodb.com.req \ tests/trust_dir/build/127.0.0.1.key \ tests/trust_dir/build/alt.mongodb.com.crt \ tests/trust_dir/build/alt.mongodb.com.key \ tests/trust_dir/verify/mongo_root.pem \ tests/trust_dir/verify/rev.mongodb.com.pem \ tests/trust_dir/verify/mongodb.com.pem \ tests/trust_dir/verify/pass.mongodb.com.pem \ tests/trust_dir/verify/127.0.0.1.pem \ tests/trust_dir/verify/alt.mongodb.com.pem \ tests/trust_dir/ca.db.index.old \ tests/trust_dir/ca.db.rand \ tests/trust_dir/signing-ca.key \ tests/trust_dir/signing-ca.crt \ tests/trust_dir/ca.db.index.attr.old \ tests/trust_dir/ca.db.serial.old \ tests/trust_dir/crl/root.crl.pem .PHONY: test_certs valgrind debug EXTRA_DIST += \ tests/abicheck.sh \ tests/binary/delete1.dat \ tests/binary/empty.dat \ tests/binary/get_more1.dat \ tests/binary/gridfs.dat \ tests/binary/gridfs-large.dat \ tests/binary/insert1.dat \ tests/binary/kill_cursors1.dat \ tests/binary/msg1.dat \ tests/binary/query1.dat \ tests/binary/query2.dat \ tests/binary/reply1.dat \ tests/binary/reply2.dat \ tests/binary/update1.dat \ tests/certificates/ca.pem \ tests/certificates/client.pem \ tests/mock_server/future-value.h \ tests/mock_server/future.c \ tests/mock_server/future.h \ tests/mock_server/mock-server.c \ tests/mock_server/mock-server.h \ tests/mock_server/mock-rs.c \ tests/mock_server/mock-rs.h \ tests/mock_server/request.c \ tests/mock_server/request.h \ tests/mock_server/sync-queue.c \ tests/mock_server/sync-queue.h \ tests/mongoc-tests.c \ tests/mongoc-tests.h \ tests/trust_dir.cnf \ tests/make_ca.pl \ tests/c_rehash \ $(wildcard tests/json/server_discovery_and_monitoring/*/*.json) \ $(wildcard tests/json/server_selection/rtt/*.json) \ $(wildcard tests/json/server_selection/server_selection/*/*/*.json) if OS_DARWIN DEBUGGER = lldb -- else DEBUGGER = gdb --args endif debug: test-libmongoc $(LIBTOOL) --mode=execute $(DEBUGGER) test-libmongoc $(TEST_ARGS) -f -p libmongoc-1.3.1/tests/TestSuite.c000066400000000000000000000470131264720626300167410ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include "mongoc-log.h" #include "mongoc-log-private.h" #if defined(__APPLE__) # include #endif #include #include #include #if !defined(_WIN32) # include # include # include # include # include # include #else # include #endif #if defined(BSON_HAVE_CLOCK_GETTIME) # include # include #endif #include "test-libmongoc.h" #include "TestSuite.h" #define TEST_VERBOSE (1 << 0) #define TEST_NOFORK (1 << 1) #define TEST_HELPONLY (1 << 2) #define TEST_NOTHREADS (1 << 3) #define TEST_DEBUGOUTPUT (1 << 4) #define TEST_TRACE (1 << 5) #define NANOSEC_PER_SEC 1000000000UL #if !defined(_WIN32) # include # define Mutex pthread_mutex_t # define Mutex_Init(_n) pthread_mutex_init((_n), NULL) # define Mutex_Lock pthread_mutex_lock # define Mutex_Unlock pthread_mutex_unlock # define Mutex_Destroy pthread_mutex_destroy # define Thread pthread_t # define Thread_Create(_t,_f,_d) pthread_create((_t), NULL, (_f), (_d)) # define Thread_Join(_n) pthread_join((_n), NULL) #else # define Mutex CRITICAL_SECTION # define Mutex_Init InitializeCriticalSection # define Mutex_Lock EnterCriticalSection # define Mutex_Unlock LeaveCriticalSection # define Mutex_Destroy DeleteCriticalSection # define Thread HANDLE # define Thread_Join(_n) WaitForSingleObject ((_n), INFINITE) # define strdup _strdup #endif #if !defined(Memory_Barrier) # define Memory_Barrier() bson_memory_barrier() #endif # define AtomicInt_DecrementAndTest(p) (bson_atomic_int_add(p, -1) == 0) #if !defined(BSON_HAVE_TIMESPEC) struct timespec { time_t tv_sec; long tv_nsec; }; #endif #if defined(_WIN32) static int Thread_Create (Thread *thread, void *(*cb)(void *), void *arg) { *thread = CreateThread (NULL, 0, (void *)cb, arg, 0, NULL); return 0; } #endif #if defined(_WIN32) && !defined(BSON_HAVE_SNPRINTF) static int snprintf (char *str, size_t size, const char *format, ...) { int r = -1; va_list ap; va_start (ap, format); if (size != 0) { r = _vsnprintf_s (str, size, _TRUNCATE, format, ap); } if (r == -1) { r = _vscprintf (format, ap); } va_end (ap); return r; } #endif void _Print_StdOut (const char *format, ...) { va_list ap; va_start (ap, format); vprintf (format, ap); fflush (stdout); va_end (ap); } void _Print_StdErr (const char *format, ...) { va_list ap; va_start (ap, format); vfprintf (stderr, format, ap); fflush (stderr); va_end (ap); } void _Clock_GetMonotonic (struct timespec *ts) /* OUT */ { #if defined(BSON_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) clock_gettime (CLOCK_MONOTONIC, ts); #elif defined(__APPLE__) static mach_timebase_info_data_t info = { 0 }; static double ratio; uint64_t atime; if (!info.denom) { mach_timebase_info(&info); ratio = info.numer / info.denom; } atime = mach_absolute_time() * ratio; ts->tv_sec = atime * 1e-9; ts->tv_nsec = atime - (ts->tv_sec * 1e9); #elif defined(_WIN32) ULONGLONG ticks = GetTickCount64 (); ts->tv_sec = ticks / NANOSEC_PER_SEC; ts->tv_nsec = ticks % NANOSEC_PER_SEC; #else # warning "Monotonic clock is not yet supported on your platform." #endif } void _Clock_Subtract (struct timespec *ts, /* OUT */ struct timespec *x, /* IN */ struct timespec *y) /* IN */ { struct timespec r; ASSERT (x); ASSERT (y); r.tv_sec = (x->tv_sec - y->tv_sec); if ((r.tv_nsec = (x->tv_nsec - y->tv_nsec)) < 0) { r.tv_nsec += NANOSEC_PER_SEC; r.tv_sec -= 1; } *ts = r; } static void TestSuite_SeedRand (TestSuite *suite, /* IN */ Test *test) /* IN */ { #ifndef BSON_OS_WIN32 int fd = open ("/dev/urandom", O_RDONLY); int n_read; unsigned seed; if (fd != -1) { n_read = read (fd, &seed, 4); assert (n_read == 4); close (fd); test->seed = seed; return; } else { test->seed = (unsigned)time (NULL) * (unsigned)getpid (); } #else test->seed = (unsigned)time (NULL); #endif } void TestSuite_Init (TestSuite *suite, const char *name, int argc, char **argv) { const char *filename; int i; memset (suite, 0, sizeof *suite); suite->name = strdup (name); suite->flags = 0; suite->prgname = strdup (argv [0]); for (i = 0; i < argc; i++) { if (0 == strcmp ("-v", argv [i])) { suite->flags |= TEST_VERBOSE; } else if (0 == strcmp ("-d", argv [i])) { suite->flags |= TEST_DEBUGOUTPUT; } else if (0 == strcmp ("-f", argv [i])) { suite->flags |= TEST_NOFORK; } else if (0 == strcmp ("-p", argv [i])) { suite->flags |= TEST_NOTHREADS; } else if ((0 == strcmp ("-t", argv [i])) || (0 == strcmp ("--trace", argv [i]))) { #ifdef MONGOC_TRACE suite->flags |= TEST_TRACE; #else _Print_StdErr ("-t requires mongoc compiled with --enable-tracing.\n"); exit (EXIT_FAILURE); #endif } else if (0 == strcmp ("-F", argv [i])) { if (argc - 1 == i) { _Print_StdErr ("-F requires a filename argument.\n"); exit (EXIT_FAILURE); } filename = argv [++i]; if (0 != strcmp ("-", filename)) { #ifdef _WIN32 if (0 != fopen_s (&suite->outfile, filename, "w")) { suite->outfile = NULL; } #else suite->outfile = fopen (filename, "w"); #endif if (!suite->outfile) { _Print_StdErr ("Failed to open log file: %s\n", filename); } } } else if ((0 == strcmp ("-h", argv [i])) || (0 == strcmp ("--help", argv [i]))) { suite->flags |= TEST_HELPONLY; } else if ((0 == strcmp ("-l", argv [i]))) { if (argc - 1 == i) { _Print_StdErr ("-l requires an argument.\n"); exit (EXIT_FAILURE); } suite->testname = strdup (argv [++i]); } } } static int TestSuite_CheckDummy (void) { return 1; } static void TestSuite_AddHelper (void *cb_) { TestFunc cb = (TestFunc)cb_; cb(); } void TestSuite_Add (TestSuite *suite, /* IN */ const char *name, /* IN */ TestFunc func) /* IN */ { TestSuite_AddFull (suite, name, TestSuite_AddHelper, NULL, (void *)func, TestSuite_CheckDummy); } void TestSuite_AddWC (TestSuite *suite, /* IN */ const char *name, /* IN */ TestFuncWC func, /* IN */ TestFuncDtor dtor, /* IN */ void *ctx) /* IN */ { TestSuite_AddFull (suite, name, func, dtor, ctx, TestSuite_CheckDummy); } void TestSuite_AddFull (TestSuite *suite, /* IN */ const char *name, /* IN */ TestFuncWC func, /* IN */ TestFuncDtor dtor, /* IN */ void *ctx, int (*check) (void)) /* IN */ { Test *test; Test *iter; test = (Test *)calloc (1, sizeof *test); test->name = strdup (name); test->func = func; test->check = check; test->next = NULL; test->dtor = dtor; test->ctx = ctx; TestSuite_SeedRand (suite, test); if (!suite->tests) { suite->tests = test; return; } for (iter = suite->tests; iter->next; iter = iter->next) { } iter->next = test; } #if !defined(_WIN32) static int TestSuite_RunFuncInChild (TestSuite *suite, /* IN */ Test *test) /* IN */ { pid_t child; int exit_code = -1; int fd; if (suite->outfile) { fflush (suite->outfile); } if (-1 == (child = fork())) { return -1; } if (!child) { if (suite->outfile) { fclose (suite->outfile); suite->outfile = NULL; } fd = open ("/dev/null", O_WRONLY); dup2 (fd, STDOUT_FILENO); close (fd); srand (test->seed); test->func (test->ctx); TestSuite_Destroy (suite); exit (0); } if (-1 == waitpid (child, &exit_code, 0)) { perror ("waitpid()"); } return exit_code; } #endif static int TestSuite_RunTest (TestSuite *suite, /* IN */ Test *test, /* IN */ Mutex *mutex, /* IN */ int *count) /* INOUT */ { struct timespec ts1; struct timespec ts2; struct timespec ts3; char name[MAX_TEST_NAME_LENGTH]; char buf[MAX_TEST_NAME_LENGTH + 500]; int status = 0; snprintf (name, sizeof name, "%s%s", suite->name, test->name); name [sizeof name - 1] = '\0'; if (!test->check || test->check ()) { _Clock_GetMonotonic (&ts1); /* * TODO: If not verbose, close()/dup(/dev/null) for stdout. */ /* Tracing is superduper slow */ #ifdef MONGOC_TRACE if (suite->flags & TEST_TRACE) { mongoc_log_set_handler (mongoc_log_default_handler, NULL); mongoc_log_trace_enable (); } else { mongoc_log_trace_disable (); } #endif #if defined(_WIN32) srand (test->seed); if (suite->flags & TEST_DEBUGOUTPUT) { _Print_StdOut ("Begin %s\n", name); } test->func (test->ctx); status = 0; #else if (suite->flags & TEST_DEBUGOUTPUT) { _Print_StdOut ("Begin %s\n", name); } if ((suite->flags & TEST_NOFORK)) { srand (test->seed); test->func (test->ctx); status = 0; } else { status = TestSuite_RunFuncInChild (suite, test); } #endif _Clock_GetMonotonic (&ts2); _Clock_Subtract (&ts3, &ts2, &ts1); Mutex_Lock (mutex); snprintf (buf, sizeof buf, " { \"status\": \"%s\", " "\"name\": \"%s\", " "\"seed\": \"%u\", " "\"elapsed\": %u.%09u }%s\n", (status == 0) ? "PASS" : "FAIL", name, test->seed, (unsigned)ts3.tv_sec, (unsigned)ts3.tv_nsec, ((*count) == 1) ? "" : ","); buf [sizeof buf - 1] = 0; _Print_StdOut ("%s", buf); if (suite->outfile) { fprintf (suite->outfile, "%s", buf); fflush (suite->outfile); } Mutex_Unlock (mutex); } else { status = 0; Mutex_Lock (mutex); snprintf (buf, sizeof buf, " { \"status\": \"SKIP\", \"name\": \"%s\" },\n", test->name); buf [sizeof buf - 1] = '\0'; _Print_StdOut ("%s", buf); if (suite->outfile) { fprintf (suite->outfile, "%s", buf); fflush (suite->outfile); } Mutex_Unlock (mutex); } return status ? 1 : 0; } static void TestSuite_PrintHelp (TestSuite *suite, /* IN */ FILE *stream) /* IN */ { Test *iter; fprintf (stream, "usage: %s [OPTIONS]\n" "\n" "Options:\n" " -h, --help Show this help menu.\n" " -f Do not fork() before running tests.\n" " -l NAME Run test by name, e.g. \"/Client/command\" or \"/Client/*\".\n" " -p Do not run tests in parallel.\n" " -v Be verbose with logs.\n" " -F FILENAME Write test results (JSON) to FILENAME.\n" " -d Print debug output (useful if a test hangs).\n" " -t, --trace Enable mongoc tracing (useful to debug tests).\n" "\n" "Tests:\n", suite->prgname); for (iter = suite->tests; iter; iter = iter->next) { fprintf (stream, " %s%s\n", suite->name, iter->name); } fprintf (stream, "\n"); } static void TestSuite_PrintJsonHeader (TestSuite *suite, /* IN */ FILE *stream) /* IN */ { char *uri_str = test_framework_get_uri_str (); #ifdef _WIN32 # define INFO_BUFFER_SIZE 32767 SYSTEM_INFO si; DWORD version = 0; DWORD major_version = 0; DWORD minor_version = 0; DWORD build = 0; GetSystemInfo(&si); version = GetVersion(); major_version = (DWORD)(LOBYTE(LOWORD(version))); minor_version = (DWORD)(HIBYTE(LOWORD(version))); if (version < 0x80000000) { build = (DWORD)(HIWORD(version)); } fprintf (stream, "{\n" " \"uri\": \"%s\",\n" " \"is_mongos\": \"%s\",\n" " \"host\": {\n" " \"sysname\": \"Windows\",\n" " \"release\": \"%ld.%ld (%ld)\",\n" " \"machine\": \"%ld\",\n" " \"memory\": {\n" " \"pagesize\": %ld,\n" " \"npages\": %d\n" " }\n" " },\n" " \"options\": {\n" " \"parallel\": \"%s\",\n" " \"fork\": \"%s\"\n" " \"tracing\": \"%s\"\n" " },\n" " \"tests\": [\n", uri_str, test_framework_is_mongos () ? "true" : "false", major_version, minor_version, build, si.dwProcessorType, si.dwPageSize, 0, (suite->flags & TEST_NOTHREADS) ? "false" : "true", (suite->flags & TEST_NOFORK) ? "false" : "true", (suite->flags & TEST_TRACE) ? "true" : "false"); #else struct utsname u; uint64_t pagesize; uint64_t npages = 0; ASSERT (suite); if (uname (&u) == -1) { perror ("uname()"); return; } pagesize = sysconf (_SC_PAGE_SIZE); # if defined(_SC_PHYS_PAGES) npages = sysconf (_SC_PHYS_PAGES); # endif fprintf (stream, "{\n" " \"uri\": \"%s\",\n" " \"is_mongos\": \"%s\",\n" " \"host\": {\n" " \"sysname\": \"%s\",\n" " \"release\": \"%s\",\n" " \"machine\": \"%s\",\n" " \"memory\": {\n" " \"pagesize\": %"PRIu64",\n" " \"npages\": %"PRIu64"\n" " }\n" " },\n" " \"options\": {\n" " \"parallel\": \"%s\",\n" " \"fork\": \"%s\"\n" " \"tracing\": \"%s\"\n" " },\n" " \"tests\": [\n", uri_str, test_framework_is_mongos () ? "true" : "false", u.sysname, u.release, u.machine, pagesize, npages, (suite->flags & TEST_NOTHREADS) ? "false" : "true", (suite->flags & TEST_NOFORK) ? "false" : "true", (suite->flags & TEST_TRACE) ? "true" : "false"); #endif fflush (stream); bson_free (uri_str); } static void TestSuite_PrintJsonFooter (FILE *stream) /* IN */ { fprintf (stream, " ]\n}\n"); fflush (stream); } typedef struct { TestSuite *suite; Test *test; Mutex *mutex; int *count; } ParallelInfo; static void * TestSuite_ParallelWorker (void *data) /* IN */ { ParallelInfo *info = (ParallelInfo *)data; int status; ASSERT (info); status = TestSuite_RunTest (info->suite, info->test, info->mutex, info->count); if (AtomicInt_DecrementAndTest (info->count)) { TestSuite_PrintJsonFooter (stdout); if (info->suite->outfile) { TestSuite_PrintJsonFooter (info->suite->outfile); } exit (status); } return NULL; } static void TestSuite_RunParallel (TestSuite *suite) /* IN */ { ParallelInfo *info; Thread *threads; Mutex mutex; Test *test; int count = 0; int i; ASSERT (suite); Mutex_Init (&mutex); for (test = suite->tests; test; test = test->next) { count++; } threads = (Thread *)calloc (count, sizeof *threads); Memory_Barrier (); for (test = suite->tests, i = 0; test; test = test->next, i++) { info = (ParallelInfo *)calloc (1, sizeof *info); info->suite = suite; info->test = test; info->count = &count; info->mutex = &mutex; Thread_Create (&threads [i], TestSuite_ParallelWorker, info); } #ifdef _WIN32 Sleep (30000); #else sleep (30); #endif _Print_StdErr ("Timed out, aborting!\n"); abort (); } static int TestSuite_RunSerial (TestSuite *suite) /* IN */ { Test *test; Mutex mutex; int count = 0; int status = 0; Mutex_Init (&mutex); for (test = suite->tests; test; test = test->next) { count++; } for (test = suite->tests; test; test = test->next) { status += TestSuite_RunTest (suite, test, &mutex, &count); count--; } TestSuite_PrintJsonFooter (stdout); if (suite->outfile) { TestSuite_PrintJsonFooter (suite->outfile); } Mutex_Destroy (&mutex); return status; } static int TestSuite_RunNamed (TestSuite *suite, /* IN */ const char *testname) /* IN */ { Mutex mutex; char name[128]; Test *test; int count = 1; bool star = strlen (testname) && testname[strlen (testname) - 1] == '*'; bool match; int status = 0; ASSERT (suite); ASSERT (testname); Mutex_Init (&mutex); for (test = suite->tests; test; test = test->next) { snprintf (name, sizeof name, "%s%s", suite->name, test->name); name [sizeof name - 1] = '\0'; if (star) { /* e.g. testname is "/Client*" and name is "/Client/authenticate" */ match = (0 == strncmp (name, testname, strlen (testname) - 1)); } else { match = (0 == strcmp (name, testname)); } if (match) { status += TestSuite_RunTest (suite, test, &mutex, &count); } } TestSuite_PrintJsonFooter (stdout); if (suite->outfile) { TestSuite_PrintJsonFooter (suite->outfile); } Mutex_Destroy (&mutex); return status; } int TestSuite_Run (TestSuite *suite) /* IN */ { int failures = 0; if ((suite->flags & TEST_HELPONLY)) { TestSuite_PrintHelp (suite, stderr); return 0; } TestSuite_PrintJsonHeader (suite, stdout); if (suite->outfile) { TestSuite_PrintJsonHeader (suite, suite->outfile); } if (suite->tests) { if (suite->testname) { failures += TestSuite_RunNamed (suite, suite->testname); } else if ((suite->flags & TEST_NOTHREADS)) { failures += TestSuite_RunSerial (suite); } else { TestSuite_RunParallel (suite); } } else { TestSuite_PrintJsonFooter (stdout); if (suite->outfile) { TestSuite_PrintJsonFooter (suite->outfile); } } return failures; } void TestSuite_Destroy (TestSuite *suite) { Test *test; Test *tmp; for (test = suite->tests; test; test = tmp) { tmp = test->next; if (test->dtor) { test->dtor(test->ctx); } free (test->name); free (test); } if (suite->outfile) { fclose (suite->outfile); } free (suite->name); free (suite->prgname); free (suite->testname); } libmongoc-1.3.1/tests/TestSuite.h000066400000000000000000000141311264720626300167410ustar00rootroot00000000000000/* * Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef TEST_SUITE_H #define TEST_SUITE_H #include #ifdef __cplusplus extern "C" { #endif #ifndef BINARY_DIR # define BINARY_DIR "tests/binary" #endif #ifdef ASSERT # undef ASSERT #endif #define ASSERT assert #ifdef ASSERT_OR_PRINT # undef ASSERT_OR_PRINT #endif #define ASSERT_OR_PRINT(_statement, _err) \ do { \ if (! (_statement)) { \ fprintf(stderr, "FAIL:%s:%d %s()\n %s\n %s\n\n", \ __FILE__, __LINE__, BSON_FUNC, \ #_statement, _err.message); \ fflush(stderr); \ abort(); \ } \ } while (0) #define ASSERT_CMPINT_HELPER(a, eq, b, fmt) \ do { \ if (!((a) eq (b))) { \ fprintf(stderr, "FAIL\n\nAssert Failure: %" fmt " %s %" fmt "\n" \ "%s:%d %s()\n", \ a, #eq, b, \ __FILE__, __LINE__, BSON_FUNC); \ abort(); \ } \ } while (0) #define ASSERT_CMPINT(a, eq, b) ASSERT_CMPINT_HELPER(a, eq, b, "d") #define ASSERT_CMPUINT(a, eq, b) ASSERT_CMPINT_HELPER(a, eq, b, "u") #define ASSERT_CMPLONG(a, eq, b) ASSERT_CMPINT_HELPER(a, eq, b, "ld") #define ASSERT_CMPULONG(a, eq, b) ASSERT_CMPINT_HELPER(a, eq, b, "lu") #define ASSERT_CMPINT64(a, eq, b) ASSERT_CMPINT_HELPER(a, eq, b, PRId64) #define ASSERT_CMPUINT64(a, eq, b) ASSERT_CMPINT_HELPER(a, eq, b, PRIu64) #define ASSERT_CMPSIZE_T(a, eq, b) ASSERT_CMPINT_HELPER(a, eq, b, "zd") #define ASSERT_CMPSSIZE_T(a, eq, b) ASSERT_CMPINT_HELPER(a, eq, b, "zx") #define ASSERT_MEMCMP(a, b, n) \ do { \ if (0 != memcmp(a, b, n)) { \ fprintf (stderr, \ "Failed comparing %d bytes: \"%.*s\" != \"%.*s\"", \ n, n, (char *) a, n, (char *) b); \ abort (); \ }\ } while (0) #ifdef ASSERT_ALMOST_EQUAL # undef ASSERT_ALMOST_EQUAL #endif #define ASSERT_ALMOST_EQUAL(a, b) \ do { \ /* evaluate once */ \ int64_t _a = (a); \ int64_t _b = (b); \ if (!(_a > (_b * 4) / 5 && (_a < (_b * 6) / 5))) { \ fprintf(stderr, "FAIL\n\nAssert Failure: %" PRId64 \ " not within 20%% of %" PRId64 "\n" \ "%s:%d %s()\n", \ _a, _b, \ __FILE__, __LINE__, BSON_FUNC); \ abort(); \ } \ } while (0) #define ASSERT_CMPSTR(a, b) \ do { \ if (((a) != (b)) && !!strcmp((a), (b))) { \ fprintf(stderr, "FAIL\n\nAssert Failure: \"%s\" != \"%s\"\n", \ a, b); \ abort(); \ } \ } while (0) #define ASSERT_CMPOID(a, b) \ do { \ if (bson_oid_compare ((a), (b))) { \ char oid_a[25]; \ char oid_b[25]; \ bson_oid_to_string ((a), oid_a); \ bson_oid_to_string ((b), oid_b); \ fprintf(stderr, \ "FAIL\n\nAssert Failure: " \ "ObjectId(\"%s\") != ObjectId(\"%s\")\n", \ oid_a, oid_b); \ abort(); \ } \ } while (0) #define ASSERT_CONTAINS(a, b) \ do { \ if (NULL == strstr ((a), (b))) { \ fprintf(stderr, \ "FAIL\n\nAssert Failure: \"%s\" does not contain \"%s\"\n", \ a, b); \ abort(); \ } \ } while (0) #define ASSERT_STARTSWITH(a, b) \ do { \ if ((a) != strstr ((a), (b))) { \ fprintf(stderr, \ "FAIL\n\nAssert Failure: \"%s\" does not start with \"%s\"\n", \ a, b); \ abort(); \ } \ } while (0) #define AWAIT(_condition) \ do { \ int64_t _start = bson_get_monotonic_time (); \ while (! (_condition)) { \ if (bson_get_monotonic_time() - _start > 1000 * 1000) { \ fprintf (stderr, \ "%s:%d %s(): \"%s\" still false after 1 second\n", \ __FILE__, __LINE__, BSON_FUNC, #_condition); \ abort (); \ } \ } \ } while (0) #define ASSERT_ERROR_CONTAINS(error, _domain, _code, _message) \ do { \ ASSERT_CMPINT (error.domain, ==, _domain); \ ASSERT_CMPINT (error.code, ==, _code); \ ASSERT_CONTAINS (error.message, _message); \ } while (0); #define MAX_TEST_NAME_LENGTH 500 typedef void (*TestFunc) (void); typedef void (*TestFuncWC) (void*); typedef void (*TestFuncDtor) (void*); typedef struct _Test Test; typedef struct _TestSuite TestSuite; struct _Test { Test *next; char *name; TestFuncWC func; TestFuncDtor dtor; void *ctx; int exit_code; unsigned seed; int (*check) (void); }; struct _TestSuite { char *prgname; char *name; char *testname; Test *tests; FILE *outfile; int flags; }; void TestSuite_Init (TestSuite *suite, const char *name, int argc, char **argv); void TestSuite_Add (TestSuite *suite, const char *name, TestFunc func); void TestSuite_AddWC (TestSuite *suite, const char *name, TestFuncWC func, TestFuncDtor dtor, void *ctx); void TestSuite_AddFull (TestSuite *suite, const char *name, TestFuncWC func, TestFuncDtor dtor, void *ctx, int (*check) (void)); int TestSuite_Run (TestSuite *suite); void TestSuite_Destroy (TestSuite *suite); #ifdef __cplusplus } #endif #endif /* TEST_SUITE_H */ libmongoc-1.3.1/tests/abicheck.sh000077500000000000000000000005271264720626300167330ustar00rootroot00000000000000#! /bin/sh cpp -P ${cppargs} ${1:-./src/libmongoc.symbols} | sed -e '/^$/d' -e 's/ G_GNUC.*$//' -e 's/ PRIVATE//' -e 's/ DATA//' | sort > expected-abi nm -D -g --defined-only .libs/libmongoc-1.0.so | cut -d ' ' -f 3 | egrep -v '^(__bss_start|_edata|_end)' | sort > actual-abi diff -u expected-abi actual-abi && rm -f expected-abi actual-abi libmongoc-1.3.1/tests/binary/000077500000000000000000000000001264720626300161235ustar00rootroot00000000000000libmongoc-1.3.1/tests/binary/delete1.dat000066400000000000000000000000471264720626300201410ustar00rootroot00000000000000'ÒÿÿÿÿÖtest.testlibmongoc-1.3.1/tests/binary/empty.dat000066400000000000000000000000001264720626300177410ustar00rootroot00000000000000libmongoc-1.3.1/tests/binary/get_more1.dat000066400000000000000000000000521264720626300204740ustar00rootroot00000000000000*ÒÿÿÿÿÕtest.testNa¼libmongoc-1.3.1/tests/binary/gridfs-large.dat000066400000000000000000007765121264720626300212050ustar00rootroot00000000000000Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. libmongoc-1.3.1/tests/binary/gridfs.dat000066400000000000000000000046721264720626300201040ustar00rootroot00000000000000Bacon ipsum dolor sit amet capicola meatloaf prosciutto, pork swine biltong hamburger brisket pancetta venison fatback tenderloin pastrami frankfurter jowl. Short ribs ball tip rump doner t-bone. Shank flank short loin biltong pig. T-bone swine capicola, pork loin pork chop ribeye cow salami brisket shank meatloaf turducken. Venison short ribs beef, meatloaf salami spare ribs jerky biltong frankfurter bresaola boudin jowl pork loin meatball short loin. Chicken cow tri-tip bacon jerky prosciutto t-bone pork chop pork beef. Strip steak ball tip tail, rump swine pork prosciutto short ribs drumstick venison pork belly beef ribs ribeye. Kevin swine turducken leberkas pastrami filet mignon shoulder brisket. Short loin kevin jerky, t-bone salami turducken ball tip doner boudin fatback turkey pork loin. Pork chop andouille leberkas short loin drumstick bresaola t-bone tenderloin rump shoulder jowl shank beef. Hamburger pork loin pancetta jowl sausage, short ribs flank. Hamburger frankfurter beef fatback spare ribs ribeye. Kielbasa chicken kevin bresaola corned beef tail cow pork chop fatback. Brisket pork chop meatloaf, corned beef flank sausage shank turkey kielbasa kevin. Shoulder shankle salami, filet mignon bacon tenderloin prosciutto kevin flank drumstick ribeye pig. Cow jerky ball tip drumstick sirloin pig pork beef ribs prosciutto leberkas. Ball tip t-bone ham, pig ham hock chuck meatloaf tail boudin turducken. Frankfurter chuck beef corned beef bresaola cow pancetta capicola turkey andouille. Pork ribeye frankfurter pastrami, chuck turkey meatball. Pig t-bone bacon drumstick ham hock capicola pork loin bresaola meatball kevin tri-tip. Biltong beef ribs jowl short ribs drumstick flank, strip steak t-bone sausage capicola pork loin frankfurter corned beef. Doner pork drumstick salami biltong. Pastrami cow ribeye beef drumstick salami, biltong beef ribs flank turducken pork belly meatball spare ribs swine. Flank leberkas doner, pork shank ham hock drumstick pork loin corned beef. Turducken shankle sirloin boudin venison ball tip pancetta. Tenderloin shank ham swine, fatback pastrami ground round kevin beef ribs ham hock turducken spare ribs leberkas meatball. Spare ribs andouille brisket beef ribs tail, bresaola swine. Strip steak bresaola sausage t-bone kevin chicken beef swine corned beef ball tip ham hock jerky kielbasa chuck. Tail venison salami pancetta beef, frankfurter bresaola beef ribs turkey ham ham hock turducken meatball rump jerky. libmongoc-1.3.1/tests/binary/insert1.dat000066400000000000000000000002021264720626300201740ustar00rootroot00000000000000‚ÒÿÿÿÿÒtest.testlibmongoc-1.3.1/tests/binary/kill_cursors1.dat000066400000000000000000000001001264720626300214000ustar00rootroot00000000000000@Òÿÿÿÿ×libmongoc-1.3.1/tests/binary/msg1.dat000066400000000000000000000000501264720626300174570ustar00rootroot00000000000000(Òÿÿÿÿèthis is a test message.libmongoc-1.3.1/tests/binary/query1.dat000066400000000000000000000000601264720626300200370ustar00rootroot000000000000000ÒÿÿÿÿÔtest.testlibmongoc-1.3.1/tests/binary/query2.dat000066400000000000000000000000531264720626300200420ustar00rootroot00000000000000+ÒÿÿÿÿÔtest.testlibmongoc-1.3.1/tests/binary/reply1.dat000066400000000000000000000010301264720626300200230ustar00rootroot00000000000000ÒÿÿÿÿNa¼2dlibmongoc-1.3.1/tests/binary/reply2.dat000066400000000000000000000375541264720626300200500ustar00rootroot00000000000000l?ÒNa¼d¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.¢this is some really long here or something or otherdthis is some stupid short value or something. blah. blah blah. blah blah blah. blah blah blah blah.libmongoc-1.3.1/tests/binary/update1.dat000066400000000000000000000000541264720626300201570ustar00rootroot00000000000000,ÒÿÿÿÿÑtest.testlibmongoc-1.3.1/tests/c_rehash000077500000000000000000000102311264720626300163360ustar00rootroot00000000000000#!/usr/bin/perl # Perl c_rehash script, scan all files in a directory # and add symbolic links to their hash values. my $openssl; my $dir = "/etc/pki/tls"; my $prefix = "/usr"; if(defined $ENV{OPENSSL}) { $openssl = $ENV{OPENSSL}; } else { $openssl = "openssl"; $ENV{OPENSSL} = $openssl; } my $pwd; eval "require Cwd"; if (defined(&Cwd::getcwd)) { $pwd=Cwd::getcwd(); } else { $pwd=`pwd`; chomp($pwd); } my $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':'; # DOS/Win32 or Unix delimiter? $ENV{PATH} = "$prefix/bin" . ($ENV{PATH} ? $path_delim . $ENV{PATH} : ""); # prefix our path if(! -x $openssl) { my $found = 0; foreach (split /$path_delim/, $ENV{PATH}) { if(-x "$_/$openssl") { $found = 1; $openssl = "$_/$openssl"; last; } } if($found == 0) { print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n"; exit 0; } } if(@ARGV) { @dirlist = @ARGV; } elsif($ENV{SSL_CERT_DIR}) { @dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR}; } else { $dirlist[0] = "$dir/certs"; } if (-d $dirlist[0]) { chdir $dirlist[0]; $openssl="$pwd/$openssl" if (!-x $openssl); chdir $pwd; } foreach (@dirlist) { if(-d $_ and -w $_) { hash_dir($_); } } sub hash_dir { my %hashlist; print "Doing $_[0]\n"; chdir $_[0]; opendir(DIR, "."); my @flist = readdir(DIR); # Delete any existing symbolic links foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) { if(-l $_) { unlink $_; } } closedir DIR; FILE: foreach $fname (grep {/\.pem$/} @flist) { # Check to see if certificates and/or CRLs present. my ($cert, $crl) = check_file($fname); if(!$cert && !$crl) { print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n"; next; } link_hash_cert($fname) if($cert); link_hash_crl($fname) if($crl); } } sub check_file { my ($is_cert, $is_crl) = (0,0); my $fname = $_[0]; open IN, $fname; while() { if(/^-----BEGIN (.*)-----/) { my $hdr = $1; if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) { $is_cert = 1; last if($is_crl); } elsif($hdr eq "X509 CRL") { $is_crl = 1; last if($is_cert); } } } close IN; return ($is_cert, $is_crl); } # Link a certificate to its subject name hash value, each hash is of # the form . where n is an integer. If the hash value already exists # then we need to up the value of n, unless its a duplicate in which # case we skip the link. We check for duplicates by comparing the # certificate fingerprints sub link_hash_cert { my $fname = $_[0]; $fname =~ s/'/'\\''/g; my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in "$fname"`; chomp $hash; chomp $fprint; $fprint =~ s/^.*=//; $fprint =~ tr/://d; my $suffix = 0; # Search for an unused hash filename while(exists $hashlist{"$hash.$suffix"}) { # Hash matches: if fingerprint matches its a duplicate cert if($hashlist{"$hash.$suffix"} eq $fprint) { print STDERR "WARNING: Skipping duplicate certificate $fname\n"; return; } $suffix++; } $hash .= ".$suffix"; print "$fname => $hash\n"; $symlink_exists=eval {symlink("",""); 1}; if ($symlink_exists) { symlink $fname, $hash; } else { open IN,"<$fname" or die "can't open $fname for read"; open OUT,">$hash" or die "can't open $hash for write"; print OUT ; # does the job for small text files close OUT; close IN; } $hashlist{$hash} = $fprint; } # Same as above except for a CRL. CRL links are of the form .r sub link_hash_crl { my $fname = $_[0]; $fname =~ s/'/'\\''/g; my ($hash, $fprint) = `"$openssl" crl -hash -fingerprint -noout -in '$fname'`; chomp $hash; chomp $fprint; $fprint =~ s/^.*=//; $fprint =~ tr/://d; my $suffix = 0; # Search for an unused hash filename while(exists $hashlist{"$hash.r$suffix"}) { # Hash matches: if fingerprint matches its a duplicate cert if($hashlist{"$hash.r$suffix"} eq $fprint) { print STDERR "WARNING: Skipping duplicate CRL $fname\n"; return; } $suffix++; } $hash .= ".r$suffix"; print "$fname => $hash\n"; $symlink_exists=eval {symlink("",""); 1}; if ($symlink_exists) { symlink $fname, $hash; } else { system ("cp", $fname, $hash); } $hashlist{$hash} = $fprint; } libmongoc-1.3.1/tests/certificates/000077500000000000000000000000001264720626300173045ustar00rootroot00000000000000libmongoc-1.3.1/tests/certificates/ca.pem000066400000000000000000000020761264720626300203770ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIC9DCCAl2gAwIBAgIJAJeYVdtunBOmMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYD VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp dHkxDjAMBgNVBAoMBTEwR2VuMQ8wDQYDVQQLDAZLZXJuZWwxGjAYBgNVBAMMEU15 IENlcnQgQXV0aG9yaXR5MRswGQYJKoZIhvcNAQkBFgxyb290QGxhemFydXMwHhcN MTIxMTI3MTkwMzM5WhcNMTMxMTI3MTkwMzM5WjCBkjELMAkGA1UEBhMCVVMxETAP BgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MQ4wDAYDVQQK DAUxMEdlbjEPMA0GA1UECwwGS2VybmVsMRowGAYDVQQDDBFNeSBDZXJ0IEF1dGhv cml0eTEbMBkGCSqGSIb3DQEJARYMcm9vdEBsYXphcnVzMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDXHKZ5j5T969S5C/Gm6f2ah7gaik3zRzWm2ZoAcz/U6fBq rnha3bueXXBRWZ7d2HgN1a+JhjuYnffcdUSen9CFVxPiRCEgJmp2A8o90Kx5Bbcf 7zHobDOGs1EF3PQ2RKgXEOUjKZ/LZDbGhClsIYCD4SdFhRMqUcxc2lQMsWEaNwID AQABo1AwTjAdBgNVHQ4EFgQUB0EZOp9+xbciTre81d/k/Am4ZBYwHwYDVR0jBBgw FoAUB0EZOp9+xbciTre81d/k/Am4ZBYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B AQUFAAOBgQB6aSQNTmD4gIQEcZiOXHJVpGOHeHBOxWteMFhcBpWvt0Cv8sqLZIVq x0eAC/tQFkAVEjT+T4S4UdtxgZ44RKCZPYI00qZsyz5bNoTE8kN/bmYNjyKMVFaG 1tU+elCdOstzBLjY1aHG1oQzbyqgoiSIDpfzjlyK/tBpckFGCz6c6A== -----END CERTIFICATE----- libmongoc-1.3.1/tests/certificates/client.pem000066400000000000000000000130421264720626300212650ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 7 (0x7) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=New York, L=New York City, O=10Gen, OU=Kernel, CN=My Cert Authority/emailAddress=root@lazarus Validity Not Before: Aug 23 14:55:32 2013 GMT Not After : Jan 7 14:55:32 2041 GMT Subject: C=US, ST=New York, L=New York City, O=10Gen, OU=kerneluser, CN=client Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:ba:16:42:d4:8b:3d:5e:8a:67:9e:a7:c0:cd:4a: 9c:9c:fd:95:b9:83:bf:f4:cf:03:8c:2e:db:a9:c1: 35:58:80:f6:e2:e9:87:28:84:e3:d0:9b:68:60:51: 0e:42:84:d8:6f:e8:34:cc:18:97:79:d3:8d:d8:2f: 23:11:25:6f:69:7a:38:bb:8c:b2:29:e9:91:be:79: 8c:cc:1b:56:98:98:d3:83:2a:c5:f9:9c:86:0c:2c: 24:0e:5c:46:3b:a9:95:44:6c:c5:e0:7c:9d:03:ae: 0d:23:99:49:a4:48:dd:0e:35:a2:e5:b4:8b:86:bd: c0:c8:ce:d5:ac:c4:36:f3:9e:5f:17:00:23:8d:53: a1:43:1b:a3:61:96:36:80:4d:35:50:b5:8b:69:31: 39:b4:63:8b:96:59:5c:d1:ea:92:eb:eb:fa:1b:35: 64:44:b3:f6:f3:a6:9d:49:3a:59:e5:e1:c2:cb:98: be:29:b3:22:dd:33:97:d7:50:4f:db:c2:58:64:18: b5:8c:3c:6b:2d:21:f6:bd:8d:e5:d2:da:8d:79:fe: a7:80:75:a8:15:b9:ee:79:7f:01:31:1d:e5:e7:15: 76:53:65:f6:fe:f0:93:7d:20:3d:cc:ff:9b:ca:b2: 50:2c:1b:3a:69:d5:e6:70:cf:ac:be:7e:5c:33:c4: 6e:a7 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 4A:8B:EE:22:42:E6:F8:62:4C:86:38:8D:C5:78:95:98:C1:10:05:7C X509v3 Authority Key Identifier: keyid:07:41:19:3A:9F:7E:C5:B7:22:4E:B7:BC:D5:DF:E4:FC:09:B8:64:16 Signature Algorithm: sha1WithRSAEncryption 13:13:a8:f0:de:78:c6:b1:e0:85:cc:27:e6:04:28:44:93:1d: f1:ff:5e:81:69:33:1f:f3:76:e0:49:ca:d9:ad:aa:db:f5:a5: f8:a6:50:bb:a1:a7:40:14:e4:2f:8d:b8:21:7f:35:04:60:db: af:f0:9e:dd:a1:ca:0b:7f:03:2e:2f:19:1e:32:6e:1e:2d:87: 68:e3:37:47:a8:5b:93:d1:88:41:73:da:88:21:59:27:d4:35: 1c:6a:27:b5:c0:c6:17:ba:f3:87:c8:e1:f4:8f:43:12:bc:fa: 8d:90:d5:86:83:df:51:a5:c9:e0:92:f0:66:d0:37:61:6f:85: 24:18 -----BEGIN CERTIFICATE----- MIIDdjCCAt+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBkjELMAkGA1UEBhMCVVMx ETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MQ4wDAYD VQQKDAUxMEdlbjEPMA0GA1UECwwGS2VybmVsMRowGAYDVQQDDBFNeSBDZXJ0IEF1 dGhvcml0eTEbMBkGCSqGSIb3DQEJARYMcm9vdEBsYXphcnVzMB4XDTEzMDgyMzE0 NTUzMloXDTQxMDEwNzE0NTUzMlowbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5l dyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MQ4wDAYDVQQKDAUxMEdlbjET MBEGA1UECwwKa2VybmVsdXNlcjEPMA0GA1UEAwwGY2xpZW50MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuhZC1Is9XopnnqfAzUqcnP2VuYO/9M8DjC7b qcE1WID24umHKITj0JtoYFEOQoTYb+g0zBiXedON2C8jESVvaXo4u4yyKemRvnmM zBtWmJjTgyrF+ZyGDCwkDlxGO6mVRGzF4HydA64NI5lJpEjdDjWi5bSLhr3AyM7V rMQ2855fFwAjjVOhQxujYZY2gE01ULWLaTE5tGOLlllc0eqS6+v6GzVkRLP286ad STpZ5eHCy5i+KbMi3TOX11BP28JYZBi1jDxrLSH2vY3l0tqNef6ngHWoFbnueX8B MR3l5xV2U2X2/vCTfSA9zP+byrJQLBs6adXmcM+svn5cM8RupwIDAQABo3sweTAJ BgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0 aWZpY2F0ZTAdBgNVHQ4EFgQUSovuIkLm+GJMhjiNxXiVmMEQBXwwHwYDVR0jBBgw FoAUB0EZOp9+xbciTre81d/k/Am4ZBYwDQYJKoZIhvcNAQEFBQADgYEAExOo8N54 xrHghcwn5gQoRJMd8f9egWkzH/N24EnK2a2q2/Wl+KZQu6GnQBTkL424IX81BGDb r/Ce3aHKC38DLi8ZHjJuHi2HaOM3R6hbk9GIQXPaiCFZJ9Q1HGontcDGF7rzh8jh 9I9DErz6jZDVhoPfUaXJ4JLwZtA3YW+FJBg= -----END CERTIFICATE----- -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6FkLUiz1eimee p8DNSpyc/ZW5g7/0zwOMLtupwTVYgPbi6YcohOPQm2hgUQ5ChNhv6DTMGJd5043Y LyMRJW9peji7jLIp6ZG+eYzMG1aYmNODKsX5nIYMLCQOXEY7qZVEbMXgfJ0Drg0j mUmkSN0ONaLltIuGvcDIztWsxDbznl8XACONU6FDG6NhljaATTVQtYtpMTm0Y4uW WVzR6pLr6/obNWREs/bzpp1JOlnl4cLLmL4psyLdM5fXUE/bwlhkGLWMPGstIfa9 jeXS2o15/qeAdagVue55fwExHeXnFXZTZfb+8JN9ID3M/5vKslAsGzpp1eZwz6y+ flwzxG6nAgMBAAECggEBALYw92urjAFVFxCiA8W7aEzYhtAkaztft4R3mD/C19z4 H0CZDeig+3+RuIactY5xDIu8WHz/EseHVlg0BmxSL5ugu4z8uq8IbNaFoVFw7r7m 2ieRKFY0ZpXiXcbllynw5iEhMjeRKhWhQmH5Qb2kTTINV5j4xKa+f9Lblx7Y2Uh4 tsaOtlMwb98D2/KYJdTv5Nj1nyuSqRVhECsd00Cb6JUBGQBx8Ja0wFy9gEygq6kU w3s1XNOSnYNEo4FaVZwp5KZyCyBENcKpNUq4nXt/7ncEfVYdJck0Li3wN4Jr2J9S eHqRzh8QkHxc1Ro8ktcXaUSs9kFuwvVvb4rcGUpOMWkCgYEA9xxp8yDtFVgzMtc/ vS8xgM1Wj4SrgKKYhE2wS05BJh/41oFMzfH1FpZ1GCM983r4QgYWoT71XsBgiOMC yN2p2IbV4V44bMGKJqaVMkB91CVCUWI6piaCQb/1CJTwaXE7zPim6dlUSxxBBnRn LP50NTscRLFcCZELD3Yl7jR8XFUCgYEAwMfkNFmGtBKAwlHZ3Y3XOwPWg+jCll7s 9nhv8TU2IB9pcCRGqyOT7k1YymvYkDT2Je4JUPWEBs4cW7yD61LrQ8w8+DrE9dGo czzGPyjOAANSX0asG74UjkNIQThmyEOltVHIxYMaSqowjHRSPdA+R4Od9EdcDdfS q5SfSVFxmwsCgYBtl1thqUOcCL7EGHQ7KdfxgJ+YDMWmyfWMD4xVCYKZLurD7xop 59nDR7zslIygE/RQC7Uzk+FsQTNO4ibVAIGX9syaI5gwm3DyjURzwehMEq4ju8W4 9DEmicRZJvysNrzHvasA4RKiMQihnTQ43yyYgvuZd3MTBxF5rPNLfll89QKBgQC9 SsmiOZIR+OUjaTmS2bbQBNm7Fm8TNcxZyzKn1wb5jb57VbNqUfnskVgxEqpIFyjn X48YRqtH/1RLI5UpGXdXUBFB8Hr7oM1VsgQ7ejakPp7AXOWcLA2FDz3AhMAvvnTU 0KRihHPpgqk/EOy8M2Ej2XHcrcEO+q+quLmbRXRWtwKBgHacQiwci/2J+v0e9i52 re/2AJHKP5MwNHFe1e01iNc5EEN0G+/Ut8XW19DWf6bsxqie0ChC+xN8TUst8alT F+tXTsHHmt/lRcjTROjT5XVuoqjtU2Q0QeVeGLgvObso+fZy3ZNeQuSJjWukdMZ3 57rGT6p0OuM8qbrTzpv3JMrm -----END PRIVATE KEY----- libmongoc-1.3.1/tests/debug-stream.c000066400000000000000000000134061264720626300173660ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef DEBUG_STREAM_H #define DEBUG_STREAM_H #include #include #include "test-libmongoc.h" #define MONGOC_STREAM_DEBUG 7 typedef struct _mongoc_stream_debug_t { mongoc_stream_t vtable; mongoc_stream_t *wrapped; debug_stream_stats_t *stats; } mongoc_stream_debug_t; static int _mongoc_stream_debug_close (mongoc_stream_t *stream) { return mongoc_stream_close (((mongoc_stream_debug_t *) stream)->wrapped); } static void _mongoc_stream_debug_destroy (mongoc_stream_t *stream) { mongoc_stream_debug_t *debug_stream = (mongoc_stream_debug_t *) stream; debug_stream->stats->n_destroyed++; mongoc_stream_destroy (debug_stream->wrapped); bson_free (debug_stream); } static void _mongoc_stream_debug_failed (mongoc_stream_t *stream) { mongoc_stream_debug_t *debug_stream = (mongoc_stream_debug_t *) stream; debug_stream->stats->n_failed++; mongoc_stream_failed (debug_stream->wrapped); bson_free (debug_stream); } static int _mongoc_stream_debug_setsockopt (mongoc_stream_t *stream, int level, int optname, void *optval, socklen_t optlen) { return mongoc_stream_setsockopt (((mongoc_stream_debug_t *) stream)->wrapped, level, optname, optval, optlen); } static int _mongoc_stream_debug_flush (mongoc_stream_t *stream) { return mongoc_stream_flush (((mongoc_stream_debug_t *) stream)->wrapped); } static ssize_t _mongoc_stream_debug_readv (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { return mongoc_stream_readv (((mongoc_stream_debug_t *) stream)->wrapped, iov, iovcnt, min_bytes, timeout_msec); } static ssize_t _mongoc_stream_debug_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { return mongoc_stream_writev (((mongoc_stream_debug_t *) stream)->wrapped, iov, iovcnt, timeout_msec); } static bool _mongoc_stream_debug_check_closed (mongoc_stream_t *stream) { return mongoc_stream_check_closed ( ((mongoc_stream_debug_t *) stream)->wrapped); } static mongoc_stream_t * _mongoc_stream_debug_get_base_stream (mongoc_stream_t *stream) { mongoc_stream_t *wrapped = ((mongoc_stream_debug_t *) stream)->wrapped; /* "wrapped" is typically a mongoc_stream_buffered_t, get the real * base stream */ if (wrapped->get_base_stream) { return wrapped->get_base_stream (wrapped); } return wrapped; } mongoc_stream_t * debug_stream_new (mongoc_stream_t *stream, debug_stream_stats_t *stats) { mongoc_stream_debug_t *debug_stream; if (!stream) { return NULL; } debug_stream = (mongoc_stream_debug_t *)bson_malloc0 (sizeof *debug_stream); debug_stream->vtable.type = MONGOC_STREAM_DEBUG; debug_stream->vtable.close = _mongoc_stream_debug_close; debug_stream->vtable.destroy = _mongoc_stream_debug_destroy; debug_stream->vtable.failed = _mongoc_stream_debug_failed; debug_stream->vtable.flush = _mongoc_stream_debug_flush; debug_stream->vtable.readv = _mongoc_stream_debug_readv; debug_stream->vtable.writev = _mongoc_stream_debug_writev; debug_stream->vtable.setsockopt = _mongoc_stream_debug_setsockopt; debug_stream->vtable.check_closed = _mongoc_stream_debug_check_closed; debug_stream->vtable.get_base_stream = _mongoc_stream_debug_get_base_stream; debug_stream->wrapped = stream; debug_stream->stats = stats; return (mongoc_stream_t *)debug_stream; } mongoc_stream_t * debug_stream_initiator (const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *user_data, bson_error_t *error) { debug_stream_stats_t *stats; mongoc_stream_t *default_stream; stats = (debug_stream_stats_t *) user_data; default_stream = mongoc_client_default_stream_initiator (uri, host, stats->client, error); return debug_stream_new (default_stream, stats); } void test_framework_set_debug_stream (mongoc_client_t *client, debug_stream_stats_t *stats) { stats->client = client; mongoc_client_set_stream_initiator (client, debug_stream_initiator, stats); } #endif /* DEBUG_STREAM_H */ libmongoc-1.3.1/tests/ha-test.c000066400000000000000000000613361264720626300163610ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #ifdef __linux #include #include #endif #include #include #ifdef __FreeBSD__ #include #endif #include "ha-test.h" #ifdef BSON_OS_WIN32 #include #ifdef _MSC_VER #define PATH_MAX 1024 #define S_ISREG(b) ((b)&_S_IFREG) #define S_ISDIR(b) ((b)&_S_IFDIR) #endif #define bson_chdir _chdir #define bson_unlink _unlink #define bson_mkdir(_d, _m) _mkdir(_d) #define sleep(_n) Sleep((_n) * 1000) #else #include #define bson_mkdir mkdir #define bson_chdir chdir #define bson_unlink unlink #endif void ha_mkdir(const char * name) { char buf[1024]; if (bson_mkdir(name, 0750)) { char * err = bson_strerror_r(errno, buf, sizeof buf); fprintf(stderr, "Failed to create directory \"%s\" because of %s\n", name, err); abort(); } } mongoc_client_pool_t * ha_replica_set_create_client_pool (ha_replica_set_t *replica_set) { mongoc_client_pool_t *client; bson_string_t *str; ha_node_t *iter; char *portstr; mongoc_uri_t *uri; str = bson_string_new("mongodb://"); for (iter = replica_set->nodes; iter; iter = iter->next) { bson_string_append(str, "127.0.0.1:"); portstr = bson_strdup_printf("%hu", iter->port); bson_string_append(str, portstr); bson_free(portstr); if (iter->next) { bson_string_append(str, ","); } } bson_string_append(str, "/?replicaSet="); bson_string_append(str, replica_set->name); #ifdef MONGOC_ENABLE_SSL if (replica_set->ssl_opt) { bson_string_append(str, "&ssl=true"); } #endif uri = mongoc_uri_new (str->str); client = mongoc_client_pool_new(uri); #ifdef MONGOC_ENABLE_SSL if (replica_set->ssl_opt) { mongoc_client_pool_set_ssl_opts(client, replica_set->ssl_opt); } #endif mongoc_uri_destroy (uri); bson_string_free(str, true); return client; } mongoc_client_t * ha_replica_set_create_client (ha_replica_set_t *replica_set) { mongoc_client_t *client; bson_string_t *str; ha_node_t *iter; char *portstr; str = bson_string_new("mongodb://"); for (iter = replica_set->nodes; iter; iter = iter->next) { bson_string_append(str, "127.0.0.1:"); portstr = bson_strdup_printf("%hu", iter->port); bson_string_append(str, portstr); bson_free(portstr); if (iter->next) { bson_string_append(str, ","); } } bson_string_append(str, "/?replicaSet="); bson_string_append(str, replica_set->name); #ifdef MONGOC_ENABLE_SSL if (replica_set->ssl_opt) { bson_string_append(str, "&ssl=true"); } #endif client = mongoc_client_new(str->str); #ifdef MONGOC_ENABLE_SSL if (replica_set->ssl_opt) { mongoc_client_set_ssl_opts(client, replica_set->ssl_opt); } #endif bson_string_free(str, true); return client; } static ha_node_t * ha_node_new (const char *name, const char *repl_set, const char *dbpath, bool is_arbiter, bool is_config, bool is_router, uint16_t port) { ha_node_t *node; node = (ha_node_t *)bson_malloc0(sizeof *node); node->name = bson_strdup(name); node->repl_set = bson_strdup(repl_set); node->dbpath = bson_strdup(dbpath); node->is_arbiter = is_arbiter; node->is_config = is_config; node->is_router = is_router; node->port = port; return node; } void ha_node_setup (ha_node_t *node) { ha_mkdir(node->dbpath); } void ha_node_kill (ha_node_t *node) { #ifdef BSON_OS_UNIX if (node->pid) { int status; kill(node->pid, SIGKILL); waitpid(node->pid, &status, 0); node->pid = 0; } #else if (node->pid.is_alive) { if (! TerminateProcess(node->pid.proc, 0)) { fprintf(stderr, "Couldn't kill: %d\n", (int)GetLastError()); abort(); } WaitForSingleObject(node->pid.proc, INFINITE); CloseHandle(node->pid.proc); CloseHandle(node->pid.thread); node->pid.is_alive = 0; } #endif } #ifdef BSON_OS_WIN32 bson_ha_pid_t ha_spawn_win32_node(char **argv) { char ** argn; char path[MAX_PATH]; bson_string_t *args; STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; bool r; bson_ha_pid_t out; si.cb = sizeof(si); out.is_alive = true; args = bson_string_new(""); bson_snprintf(path, sizeof path, "%s.exe", argv[0]); if (! PathFindOnPath(path, NULL)) { fprintf(stderr, "Failed to find path to binary: %s - %s\n", path, argv[0]); abort(); } bson_string_append_printf(args, "\"%s\"", path); for (argn = argv + 1; *argn != NULL; argn++) { bson_string_append_printf(args, " \"%s\"", *argn); } r = CreateProcess(path, args->str, NULL, NULL, false, 0, NULL, NULL, &si, &pi); if (r) { out.proc = pi.hProcess; out.thread = pi.hThread; } else { out.is_alive = false; fprintf(stderr, "Failed to create %s - %s: %d\n", path, args->str, (int)GetLastError()); abort(); } bson_string_free(args, true); return out; } #endif void ha_node_restart (ha_node_t *node) { struct stat st; bson_ha_pid_t pid; char portstr[12]; char *argv[30]; int i = 0; bson_snprintf(portstr, sizeof portstr, "%hu", node->port); portstr[sizeof portstr - 1] = '\0'; ha_node_kill(node); if (!node->is_router && !node->is_config) { argv[i++] = (char *) "mongod"; argv[i++] = (char *) "--dbpath"; argv[i++] = (char *) "."; argv[i++] = (char *) "--port"; argv[i++] = portstr; argv[i++] = (char *) "--nojournal"; argv[i++] = (char *) "--noprealloc"; argv[i++] = (char *) "--smallfiles"; argv[i++] = (char *) "--nohttpinterface"; argv[i++] = (char *) "--bind_ip"; argv[i++] = (char *) "127.0.0.1"; argv[i++] = (char *) "--replSet"; argv[i++] = node->repl_set; #ifdef MONGOC_ENABLE_SSL if (node->ssl_opt) { if (node->ssl_opt->pem_file) { argv[i++] = (char *) "--sslPEMKeyFile"; argv[i++] = (char *)(node->ssl_opt->pem_file); argv[i++] = (char *) "--sslClusterFile"; argv[i++] = (char *)(node->ssl_opt->pem_file); } if (node->ssl_opt->ca_file) { argv[i++] = (char *) "--sslCAFile"; argv[i++] = (char *)(node->ssl_opt->ca_file); } argv[i++] = (char *) "--sslOnNormalPorts"; } #endif argv[i++] = "--logpath"; argv[i++] = "log"; argv[i++] = NULL; } else if (node->is_config) { argv[i++] = (char *) "mongod"; argv[i++] = (char *) "--configsvr"; argv[i++] = (char *) "--dbpath"; argv[i++] = (char *) "."; argv[i++] = (char *) "--port"; argv[i++] = (char *) portstr; argv[i++] = "--logpath"; argv[i++] = "log"; argv[i++] = NULL; } else { argv[i++] = (char *) "mongos"; argv[i++] = (char *) "--bind_ip"; argv[i++] = (char *) "127.0.0.1"; argv[i++] = (char *) "--nohttpinterface"; argv[i++] = (char *) "--port"; argv[i++] = (char *) portstr; argv[i++] = (char *) "--configdb"; argv[i++] = node->configopt; argv[i++] = "--logpath"; argv[i++] = "log"; argv[i++] = NULL; } #ifdef BSON_OS_UNIX pid = fork(); if (pid < 0) { perror("Failed to fork process"); abort(); } if (!pid) { int fd; #ifdef __linux prctl (PR_SET_PDEATHSIG, 15); #endif if (0 != chdir(node->dbpath)) { perror("Failed to chdir"); abort(); } if (0 == stat("mongod.lock", &st)) { unlink("mongod.lock"); } fd = open("/dev/null", O_RDWR); if (fd == -1) { perror("Failed to open /dev/null"); abort(); } dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); if (-1 == execvp(argv[0], argv)) { perror("Failed to spawn unix process"); abort(); } } fprintf(stderr, "[%d]: ", (int)pid); #else { char pathbuf[1024]; GetCurrentDirectory(sizeof pathbuf, pathbuf); if (0 != bson_chdir(node->dbpath)) { perror("Failed to chdir"); abort(); } if (0 == stat("mongod.lock", &st)) { bson_unlink("mongod.lock"); } pid = ha_spawn_win32_node(argv); if (! pid.is_alive) { perror("Failed to launch win32 process"); abort(); } if (0 != bson_chdir(pathbuf)) { perror("Failed to chdir"); abort(); } } #endif for (i = 0; argv[i]; i++) fprintf(stderr, "%s ", argv[i]); fprintf(stderr, "\n"); node->pid = pid; } static void ha_node_destroy (ha_node_t *node) { ha_node_kill(node); bson_free(node->name); bson_free(node->repl_set); bson_free(node->dbpath); bson_free(node->configopt); bson_free(node); } static MONGOC_ONCE_FUN(random_init) { srand((unsigned)time(NULL)); MONGOC_ONCE_RETURN; } static int random_int (void) { static mongoc_once_t once = MONGOC_ONCE_INIT; mongoc_once(&once, random_init); return rand(); } static int random_int_range (int low, int high) { return low + (random_int() % (high - low)); } #ifdef MONGOC_ENABLE_SSL void ha_replica_set_ssl (ha_replica_set_t *repl_set, mongoc_ssl_opt_t *opt) { repl_set->ssl_opt = opt; } #endif ha_replica_set_t * ha_replica_set_new (const char *name) { ha_replica_set_t *repl_set; repl_set = (ha_replica_set_t *)bson_malloc0(sizeof *repl_set); repl_set->name = bson_strdup(name); repl_set->next_port = random_int_range(30000, 40000); return repl_set; } static ha_node_t * ha_replica_set_add_node (ha_replica_set_t *replica_set, const char *name, bool is_arbiter) { ha_node_t *node; ha_node_t *iter; char dbpath[PATH_MAX]; bson_snprintf(dbpath, sizeof dbpath, "%s/%s", replica_set->name, name); dbpath[sizeof dbpath - 1] = '\0'; node = ha_node_new(name, replica_set->name, dbpath, is_arbiter, false, false, replica_set->next_port++); #ifdef MONGOC_ENABLE_SSL node->ssl_opt = replica_set->ssl_opt; #endif if (!replica_set->nodes) { replica_set->nodes = node; } else { for (iter = replica_set->nodes; iter->next; iter = iter->next) { } iter->next = node; } return node; } ha_node_t * ha_replica_set_add_arbiter (ha_replica_set_t *replica_set, const char *name) { return ha_replica_set_add_node(replica_set, name, true); } ha_node_t * ha_replica_set_add_replica (ha_replica_set_t *replica_set, const char *name) { return ha_replica_set_add_node(replica_set, name, false); } static void ha_replica_set_configure (ha_replica_set_t *replica_set, ha_node_t *primary) { mongoc_database_t *database; mongoc_client_t *client; mongoc_cursor_t *cursor; const bson_t *doc; bson_error_t error; bson_iter_t iter; ha_node_t *node; bson_t ar; bson_t cmd; bson_t config; bson_t member; char *str; char *uristr; char hoststr[32]; char key[8]; int i = 0; #ifdef MONGOC_ENABLE_SSL if (replica_set->ssl_opt) { uristr = bson_strdup_printf("mongodb://127.0.0.1:%hu/?ssl=true", primary->port); } else { uristr = bson_strdup_printf("mongodb://127.0.0.1:%hu/", primary->port); } #else uristr = bson_strdup_printf("mongodb://127.0.0.1:%hu/", primary->port); #endif client = mongoc_client_new(uristr); #ifdef MONGOC_ENABLE_SSL if (replica_set->ssl_opt) { mongoc_client_set_ssl_opts(client, replica_set->ssl_opt); } #endif bson_free(uristr); bson_init(&cmd); bson_append_document_begin(&cmd, "replSetInitiate", -1, &config); bson_append_utf8(&config, "_id", 3, replica_set->name, -1); bson_append_array_begin(&config, "members", -1, &ar); for (node = replica_set->nodes; node; node = node->next) { bson_snprintf(key, sizeof key, "%u", i); key[sizeof key - 1] = '\0'; bson_snprintf(hoststr, sizeof hoststr, "127.0.0.1:%hu", node->port); hoststr[sizeof hoststr - 1] = '\0'; bson_append_document_begin(&ar, key, -1, &member); bson_append_int32(&member, "_id", -1, i); bson_append_utf8(&member, "host", -1, hoststr, -1); bson_append_bool(&member, "arbiterOnly", -1, node->is_arbiter); bson_append_document_end(&ar, &member); i++; } bson_append_array_end(&config, &ar); bson_append_document_end(&cmd, &config); str = bson_as_json(&cmd, NULL); MONGOC_DEBUG("Config: %s", str); bson_free(str); database = mongoc_client_get_database(client, "admin"); again: cursor = mongoc_database_command(database, MONGOC_QUERY_NONE, 0, 1, 0, &cmd, NULL, NULL); while (mongoc_cursor_next(cursor, &doc)) { str = bson_as_json(doc, NULL); MONGOC_DEBUG("Reply: %s", str); bson_free(str); if (bson_iter_init_find(&iter, doc, "ok") && bson_iter_as_bool(&iter)) { goto cleanup; } } if (mongoc_cursor_error(cursor, &error)) { mongoc_cursor_destroy(cursor); MONGOC_WARNING("%s: Retrying in 1 second.", error.message); sleep(1); goto again; } cleanup: mongoc_cursor_destroy(cursor); mongoc_database_destroy(database); mongoc_client_destroy(client); bson_destroy(&cmd); } void ha_rm_dir(const char * name) { #ifdef BSON_OS_UNIX char * cmd; cmd = bson_strdup_printf("rm -rf \"%s\"", name); fprintf(stderr, "%s\n", cmd); if (0 != system(cmd)) { fprintf (stderr, "%s failed\n", cmd); } bson_free(cmd); #else SHFILEOPSTRUCT fos = { 0 }; char path[MAX_PATH+1] = { 0 }; int r; char curdir[1024]; GetCurrentDirectory(sizeof curdir, curdir); bson_snprintf(path, sizeof path, "%s\\%s", curdir, name); path[strlen(path)+1] = '\0'; fos.wFunc = FO_DELETE; fos.pFrom = path; fos.fFlags = FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMATION; fprintf(stderr, "win32 removing \"%s\"\n", path); r = SHFileOperation(&fos); /* file not found isn't an error. I.e. the 2 */ if (r && r != 2) { fprintf(stderr, "failure to delete %s with %d\n", name, r); abort(); } #endif } void ha_replica_set_start (ha_replica_set_t *replica_set) { struct stat st; ha_node_t *primary = NULL; ha_node_t *node; if (!stat(replica_set->name, &st)) { if (S_ISDIR(st.st_mode)) { ha_rm_dir(replica_set->name); } } ha_mkdir(replica_set->name); for (node = replica_set->nodes; node; node = node->next) { if (!primary && !node->is_arbiter) { primary = node; } ha_node_setup(node); ha_node_restart(node); } BSON_ASSERT(primary); sleep(2); ha_replica_set_configure(replica_set, primary); } void ha_replica_set_shutdown (ha_replica_set_t *replica_set) { ha_node_t *node; for (node = replica_set->nodes; node; node = node->next) { ha_node_kill(node); } } void ha_replica_set_destroy (ha_replica_set_t *replica_set) { ha_node_t *node; while ((node = replica_set->nodes)) { replica_set->nodes = node->next; ha_node_destroy(node); } bson_free(replica_set->name); bson_free(replica_set); } static bool ha_replica_set_get_status (ha_replica_set_t *replica_set, bson_t *status) { mongoc_database_t *db; mongoc_client_t *client; mongoc_cursor_t *cursor; const bson_t *doc; bool ret = false; ha_node_t *node; bson_t cmd; char *uristr; bson_init(&cmd); bson_append_int32(&cmd, "replSetGetStatus", -1, 1); for (node = replica_set->nodes; !ret && node; node = node->next) { uristr = bson_strdup_printf("mongodb://127.0.0.1:%hu/?slaveOk=true", node->port); client = mongoc_client_new(uristr); #ifdef MONGOC_ENABLE_SSL if (replica_set->ssl_opt) { mongoc_client_set_ssl_opts(client, replica_set->ssl_opt); } #endif bson_free(uristr); db = mongoc_client_get_database(client, "admin"); if ((cursor = mongoc_database_command(db, MONGOC_QUERY_SLAVE_OK, 0, 1, 0, &cmd, NULL, NULL))) { if (mongoc_cursor_next(cursor, &doc)) { bson_copy_to(doc, status); ret = true; } mongoc_cursor_destroy(cursor); } mongoc_database_destroy(db); mongoc_client_destroy(client); } return ret; } void ha_replica_set_wait_for_healthy (ha_replica_set_t *replica_set) { bson_iter_t iter; bson_iter_t ar; bson_iter_t member; const char *stateStr; bson_t status; again: sleep(1); if (!ha_replica_set_get_status(replica_set, &status)) { MONGOC_INFO("Failed to get replicaSet status. " "Sleeping 1 second."); goto again; } #if 0 { char *str; str = bson_as_json(&status, NULL); fprintf(stderr, "%s\n", str); bson_free(str); } #endif if (!bson_iter_init_find(&iter, &status, "members") || !BSON_ITER_HOLDS_ARRAY(&iter) || !bson_iter_recurse(&iter, &ar)) { bson_destroy(&status); MONGOC_INFO("ReplicaSet has not yet come online. " "Sleeping 1 second."); goto again; } while (bson_iter_next(&ar)) { if (BSON_ITER_HOLDS_DOCUMENT(&ar) && bson_iter_recurse(&ar, &member) && bson_iter_find(&member, "stateStr") && (stateStr = bson_iter_utf8(&member, NULL))) { if (!!strcmp(stateStr, "PRIMARY") && !!strcmp(stateStr, "SECONDARY") && !!strcmp(stateStr, "ARBITER")) { bson_destroy(&status); MONGOC_INFO("Found unhealthy node. Sleeping 1 second."); goto again; } } } bson_destroy(&status); } ha_sharded_cluster_t * ha_sharded_cluster_new (const char *name) { ha_sharded_cluster_t *cluster; cluster = (ha_sharded_cluster_t *)bson_malloc0(sizeof *cluster); cluster->next_port = random_int_range(40000, 41000); cluster->name = bson_strdup(name); return cluster; } void ha_sharded_cluster_add_replica_set (ha_sharded_cluster_t *cluster, ha_replica_set_t *replica_set) { int i; BSON_ASSERT (cluster); BSON_ASSERT (replica_set); for (i = 0; i < 12; i++) { if (!cluster->replicas[i]) { cluster->replicas[i] = replica_set; break; } } } ha_node_t * ha_sharded_cluster_add_config (ha_sharded_cluster_t *cluster, const char *name) { ha_node_t *node; char dbpath[PATH_MAX]; BSON_ASSERT (cluster); bson_snprintf(dbpath, sizeof dbpath, "%s/%s", cluster->name, name); dbpath[sizeof dbpath - 1] = '\0'; node = ha_node_new(name, NULL, dbpath, false, true, false, cluster->next_port++); #ifdef MONGOC_ENABLE_SSL node->ssl_opt = cluster->ssl_opt; #endif node->next = cluster->configs; cluster->configs = node; return node; } ha_node_t * ha_sharded_cluster_add_router (ha_sharded_cluster_t *cluster, const char *name) { ha_node_t *node; char dbpath[PATH_MAX]; BSON_ASSERT (cluster); bson_snprintf(dbpath, sizeof dbpath, "%s/%s", cluster->name, name); dbpath[sizeof dbpath - 1] = '\0'; node = ha_node_new(name, NULL, dbpath, false, false, true, cluster->next_port++); #ifdef MONGOC_ENABLE_SSL node->ssl_opt = cluster->ssl_opt; #endif node->next = cluster->routers; cluster->routers = node; return node; } static void ha_config_add_shard (ha_node_t *node, ha_replica_set_t *replica_set) { mongoc_collection_t *collection; mongoc_client_t *client; bson_string_t *shardstr; bson_error_t error; bool r; bson_t reply; bson_t cmd = BSON_INITIALIZER; char *uristr; uristr = bson_strdup_printf ("mongodb://127.0.0.1:%hu/", node->port); client = mongoc_client_new (uristr); collection = mongoc_client_get_collection (client, "admin", "fake"); shardstr = bson_string_new (NULL); bson_string_append_printf (shardstr, "%s/127.0.0.1:%hu", replica_set->name, replica_set->nodes->port); bson_append_utf8 (&cmd, "addShard", -1, shardstr->str, shardstr->len); bson_string_free (shardstr, true); again: sleep (1); r = mongoc_collection_command_simple (collection, &cmd, NULL, &reply, &error); if (!r) { fprintf (stderr, "%s\n", error.message); goto again; } #if 1 { char *str; str = bson_as_json (&reply, NULL); fprintf (stderr, "%s\n", str); bson_free (str); } #endif bson_destroy (&reply); bson_destroy (&cmd); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_free (uristr); } void ha_sharded_cluster_start (ha_sharded_cluster_t *cluster) { bson_string_t *configopt; struct stat st; ha_node_t *iter; int i; BSON_ASSERT (cluster); if (!stat(cluster->name, &st)) { if (S_ISDIR(st.st_mode)) { ha_rm_dir(cluster->name); } } ha_mkdir(cluster->name); for (i = 0; i < 12; i++) { if (cluster->replicas[i]) { ha_replica_set_start(cluster->replicas[i]); } } configopt = bson_string_new (NULL); for (iter = cluster->configs; iter; iter = iter->next) { ha_node_setup(iter); ha_node_restart(iter); bson_string_append_printf (configopt, "127.0.0.1:%hu%s", iter->port, iter->next ? "," : ""); } sleep (10); for (iter = cluster->routers; iter; iter = iter->next) { bson_free (iter->configopt); iter->configopt = bson_strdup (configopt->str); ha_node_setup (iter); ha_node_restart (iter); } ha_sharded_cluster_wait_for_healthy (cluster); for (i = 0; i < 12; i++) { if (cluster->replicas[i]) { ha_config_add_shard (cluster->routers, cluster->replicas[i]); } } bson_string_free (configopt, true); } void ha_sharded_cluster_wait_for_healthy (ha_sharded_cluster_t *cluster) { int i; BSON_ASSERT (cluster); for (i = 0; i < 12; i++) { if (cluster->replicas[i]) { ha_replica_set_wait_for_healthy(cluster->replicas[i]); } } } void ha_sharded_cluster_shutdown (ha_sharded_cluster_t *cluster) { ha_node_t *iter; int i; BSON_ASSERT (cluster); for (i = 0; i < 12; i++) { if (cluster->replicas[i]) { ha_replica_set_shutdown(cluster->replicas[i]); } } for (iter = cluster->configs; iter; iter = iter->next) { ha_node_kill(iter); } for (iter = cluster->routers; iter; iter = iter->next) { ha_node_kill(iter); } } mongoc_client_t * ha_sharded_cluster_get_client (ha_sharded_cluster_t *cluster) { const ha_node_t *iter; mongoc_client_t *client; bson_string_t *str; BSON_ASSERT (cluster); BSON_ASSERT (cluster->routers); str = bson_string_new ("mongodb://"); for (iter = cluster->routers; iter; iter = iter->next) { bson_string_append_printf (str, "127.0.0.1:%hu%s", iter->port, iter->next ? "," : ""); } bson_string_append (str, "/"); client = mongoc_client_new (str->str); bson_string_free (str, true); return client; } libmongoc-1.3.1/tests/ha-test.h000066400000000000000000000077271264720626300163720ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef HA_TEST_H #define HA_TEST_H #include #include #include BSON_BEGIN_DECLS typedef struct _ha_sharded_cluster_t ha_sharded_cluster_t; typedef struct _ha_replica_set_t ha_replica_set_t; typedef struct _ha_node_t ha_node_t; struct _ha_sharded_cluster_t { char *name; ha_replica_set_t *replicas[12]; ha_node_t *configs; ha_node_t *routers; int next_port; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t *ssl_opt; #endif }; struct _ha_replica_set_t { char *name; ha_node_t *nodes; int next_port; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t *ssl_opt; #endif }; #ifdef BSON_OS_WIN32 typedef struct { bool is_alive; HANDLE proc; HANDLE thread; } bson_ha_pid_t; #else typedef pid_t bson_ha_pid_t; #endif struct _ha_node_t { ha_node_t *next; char *name; char *repl_set; char *dbpath; char *configopt; bool is_arbiter : 1; bool is_config : 1; bool is_router : 1; bson_ha_pid_t pid; uint16_t port; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t *ssl_opt; #endif }; ha_replica_set_t *ha_replica_set_new (const char *name); ha_node_t *ha_replica_set_add_arbiter (ha_replica_set_t *replica_set, const char *name); ha_node_t *ha_replica_set_add_replica (ha_replica_set_t *replica_set, const char *name); mongoc_client_t *ha_replica_set_create_client (ha_replica_set_t *replica_set); mongoc_client_pool_t *ha_replica_set_create_client_pool (ha_replica_set_t *replica_set); void ha_replica_set_start (ha_replica_set_t *replica_set); void ha_replica_set_shutdown (ha_replica_set_t *replica_set); void ha_replica_set_destroy (ha_replica_set_t *replica_set); void ha_replica_set_wait_for_healthy (ha_replica_set_t *replica_set); #ifdef MONGOC_ENABLE_SSL void ha_replica_set_ssl (ha_replica_set_t *repl_set, mongoc_ssl_opt_t *opt); #endif void ha_node_kill (ha_node_t *node); void ha_node_restart (ha_node_t *node); ha_sharded_cluster_t *ha_sharded_cluster_new (const char *name); void ha_sharded_cluster_start (ha_sharded_cluster_t *cluster); void ha_sharded_cluster_wait_for_healthy (ha_sharded_cluster_t *cluster); ha_node_t * ha_sharded_cluster_add_config (ha_sharded_cluster_t *cluster, const char *name); ha_node_t * ha_sharded_cluster_add_router (ha_sharded_cluster_t *cluster, const char *name); void ha_sharded_cluster_add_replica_set (ha_sharded_cluster_t *cluster, ha_replica_set_t *replica_set); void ha_sharded_cluster_shutdown (ha_sharded_cluster_t *cluster); mongoc_client_t *ha_sharded_cluster_get_client (ha_sharded_cluster_t *cluster); BSON_END_DECLS #endif /* HA_TEST_H */ libmongoc-1.3.1/tests/json-test.c000066400000000000000000000205041264720626300167320ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "json-test.h" #ifdef _MSC_VER #include #else #include #endif mongoc_topology_description_type_t topology_type_from_test(const char *type) { if (strcmp(type, "ReplicaSetWithPrimary") == 0) { return MONGOC_TOPOLOGY_RS_WITH_PRIMARY; } else if (strcmp(type, "ReplicaSetNoPrimary") == 0) { return MONGOC_TOPOLOGY_RS_NO_PRIMARY; } else if (strcmp(type, "Unknown") == 0) { return MONGOC_TOPOLOGY_UNKNOWN; } else if (strcmp(type, "Single") == 0) { return MONGOC_TOPOLOGY_SINGLE; } else if (strcmp(type, "Sharded") == 0) { return MONGOC_TOPOLOGY_SHARDED; } fprintf(stderr, "can't parse this: %s", type); assert(0); return 0; } mongoc_server_description_type_t server_type_from_test(const char *type) { if (strcmp(type, "RSPrimary") == 0) { return MONGOC_SERVER_RS_PRIMARY; } else if (strcmp(type, "RSSecondary") == 0) { return MONGOC_SERVER_RS_SECONDARY; } else if (strcmp(type, "Standalone") == 0) { return MONGOC_SERVER_STANDALONE; } else if (strcmp(type, "Mongos") == 0) { return MONGOC_SERVER_MONGOS; } else if (strcmp(type, "PossiblePrimary") == 0) { return MONGOC_SERVER_POSSIBLE_PRIMARY; } else if (strcmp(type, "RSArbiter") == 0) { return MONGOC_SERVER_RS_ARBITER; } else if (strcmp(type, "RSOther") == 0) { return MONGOC_SERVER_RS_OTHER; } else if (strcmp(type, "RSGhost") == 0) { return MONGOC_SERVER_RS_GHOST; } else if (strcmp(type, "Unknown") == 0) { return MONGOC_SERVER_UNKNOWN; } fprintf(stderr, "ERROR: Unknown server type %s\n", type); assert(0); return 0; } const char * topology_type_to_string(mongoc_topology_description_type_t type) { switch(type) { case MONGOC_TOPOLOGY_UNKNOWN: return "Unknown"; case MONGOC_TOPOLOGY_SHARDED: return "Sharded"; case MONGOC_TOPOLOGY_RS_NO_PRIMARY: return "ReplicaSetNoPrimary"; case MONGOC_TOPOLOGY_RS_WITH_PRIMARY: return "ReplicaSetWithPrimary"; case MONGOC_TOPOLOGY_SINGLE: return "Single"; case MONGOC_TOPOLOGY_DESCRIPTION_TYPES: default: fprintf(stderr, "ERROR: Unknown topology state\n"); assert(0); } return NULL; } /* *----------------------------------------------------------------------- * * assemble_path -- * * Given a parent directory and filename, compile a full path to * the child file. * *----------------------------------------------------------------------- */ void assemble_path (const char *parent_path, const char *child_name, char *dst /* OUT */) { int path_len = (int)strlen(parent_path); int name_len = (int)strlen(child_name); assert(path_len + name_len + 1 < MAX_TEST_NAME_LENGTH); memset(dst, '\0', MAX_TEST_NAME_LENGTH * sizeof(char)); strncat(dst, parent_path, path_len); strncat(dst, "/", 1); strncat(dst, child_name, name_len); } /* *----------------------------------------------------------------------- * * collect_tests_from_dir -- * * Recursively search the directory at @dir_path for files with * '.json' in their filenames. Append all found file paths to * @paths, and return the number of files found. * *----------------------------------------------------------------------- */ int collect_tests_from_dir (char (*paths)[MAX_TEST_NAME_LENGTH] /* OUT */, const char *dir_path, int paths_index, int max_paths) { #ifdef _MSC_VER intptr_t handle; struct _finddata_t info; char child_path[MAX_TEST_NAME_LENGTH]; handle = _findfirst(dir_path, &info); if (handle == -1) { return 0; } while (1) { assert(paths_index < max_paths); if (_findnext(handle, &info) == -1) { break; } if (info.attrib & _A_SUBDIR) { /* recursively call on child directories */ if (strcmp (info.name, "..") != 0 && strcmp (info.name, ".") != 0) { assemble_path(dir_path, info.name, child_path); paths_index = collect_tests_from_dir(paths, child_path, paths_index, max_paths); } } else if (strstr(info.name, ".json")) { /* if this is a JSON test, collect its path */ assemble_path(dir_path, info.name, paths[paths_index++]); } } _findclose(handle); return paths_index; #else struct dirent *entry; struct stat dir_stat; char child_path[MAX_TEST_NAME_LENGTH]; DIR *dir; dir = opendir(dir_path); assert (dir); while ((entry = readdir(dir))) { assert(paths_index < max_paths); if (0 == stat(entry->d_name, &dir_stat) && dir_stat.st_mode & S_IFDIR) { /* recursively call on child directories */ if (strcmp (entry->d_name, "..") != 0 && strcmp (entry->d_name, ".") != 0) { assemble_path(dir_path, entry->d_name, child_path); paths_index = collect_tests_from_dir(paths, child_path, paths_index, max_paths); } } else if (strstr(entry->d_name, ".json")) { /* if this is a JSON test, collect its path */ assemble_path(dir_path, entry->d_name, paths[paths_index++]); } } closedir(dir); return paths_index; #endif } /* *----------------------------------------------------------------------- * * get_bson_from_json_file -- * * Open the file at @filename and store its contents in a * bson_t. This function assumes that @filename contains a * single JSON object. * * NOTE: caller owns returned bson_t and must free it. * *----------------------------------------------------------------------- */ bson_t * get_bson_from_json_file(char *filename) { FILE *file; long length; bson_t *data; bson_error_t error; const char *buffer; file = fopen(filename, "r"); if (!file) { return NULL; } /* get file length */ fseek(file, 0, SEEK_END); length = ftell(file); fseek(file, 0, SEEK_SET); if (length < 1) { return NULL; } /* read entire file into buffer */ buffer = (const char *)bson_malloc0(length); if (fread((void *)buffer, 1, length, file) != length) { abort(); } fclose(file); if (!buffer) { return NULL; } /* convert to bson */ data = bson_new_from_json((const uint8_t*)buffer, length, &error); bson_free((void *)buffer); if (!data) { return NULL; } return data; } /* *----------------------------------------------------------------------- * * run_json_test_suite -- * * Given a path to a directory containing JSON tests, import each * test into a BSON blob and call the provided callback for * evaluation. * * It is expected that the callback will assert on failure, so if * callback returns quietly the test is considered to have passed. * *----------------------------------------------------------------------- */ void install_json_test_suite(TestSuite *suite, const char *dir_path, test_hook callback) { char test_paths[MAX_NUM_TESTS][MAX_TEST_NAME_LENGTH]; int num_tests; int i; bson_t *test; char *skip_json; char *ext; num_tests = collect_tests_from_dir(&test_paths[0], dir_path, 0, MAX_NUM_TESTS); for (i = 0; i < num_tests; i++) { test = get_bson_from_json_file(test_paths[i]); if (test) { skip_json = strstr(test_paths[i], "/json") + strlen("/json"); assert(skip_json); ext = strstr (skip_json, ".json"); assert(ext); ext[0] = '\0'; TestSuite_AddWC(suite, skip_json, (void (*)(void *))callback, (void (*)(void*))bson_destroy, test); } else { fprintf(stderr, "NO DATA\n"); } } } libmongoc-1.3.1/tests/json-test.h000066400000000000000000000031611264720626300167370ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef JSON_TEST_H #define JSON_TEST_H #include "TestSuite.h" #include #include #include "mongoc-server-description-private.h" #include "mongoc-topology-description-private.h" #define MAX_NUM_TESTS 100 typedef void (* test_hook)(bson_t *test); bson_t * get_bson_from_json_file (char *filename); int collect_tests_from_dir (char (*paths)[MAX_TEST_NAME_LENGTH] /* OUT */, const char *dir_path, int paths_index, int max_paths); void assemble_path (const char *parent_path, const char *child_name, char *dst /* OUT */); void install_json_test_suite(TestSuite *suite, const char *dir_path, test_hook callback); mongoc_topology_description_type_t topology_type_from_test(const char *type); const char * topology_type_to_string(mongoc_topology_description_type_t type); mongoc_server_description_type_t server_type_from_test(const char *type); #endif libmongoc-1.3.1/tests/json/000077500000000000000000000000001264720626300156105ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/000077500000000000000000000000001264720626300242745ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/000077500000000000000000000000001264720626300247205ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/discover_arbiters.json000066400000000000000000000020521264720626300313230ustar00rootroot00000000000000{ "description": "Discover arbiters", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "arbiters": [ "b:27017" ], "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/discover_passives.json000066400000000000000000000041041264720626300313450ustar00rootroot00000000000000{ "description": "Discover passives", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "passives": [ "b:27017" ], "setName": "rs" } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": "rs", "type": "RSSecondary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "a:27017" ], "ismaster": false, "ok": 1, "passive": true, "passives": [ "b:27017" ], "secondary": true, "setName": "rs" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/discover_primary.json000066400000000000000000000017731264720626300312040ustar00rootroot00000000000000{ "description": "Replica set discovery from primary", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/discover_secondary.json000066400000000000000000000020521264720626300314770ustar00rootroot00000000000000{ "description": "Replica set discovery from secondary", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" }, "b:27017": { "setName": "rs", "type": "RSSecondary" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "rs" } ] ] } ], "uri": "mongodb://b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/discovery.json000066400000000000000000000117341264720626300276300ustar00rootroot00000000000000{ "description": "Replica set discovery", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSSecondary" }, "b:27017": { "setName": null, "type": "Unknown" }, "c:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017", "c:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "rs" } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSSecondary" }, "b:27017": { "setName": "rs", "type": "RSSecondary" }, "c:27017": { "setName": null, "type": "Unknown" }, "d:27017": { "setName": null, "type": "PossiblePrimary" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "b:27017", "c:27017", "d:27017" ], "ismaster": false, "ok": 1, "primary": "d:27017", "secondary": true, "setName": "rs" } ] ] }, { "outcome": { "servers": { "b:27017": { "setName": "rs", "type": "RSSecondary" }, "c:27017": { "setName": null, "type": "Unknown" }, "d:27017": { "setName": "rs", "type": "RSPrimary" }, "e:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "d:27017", { "hosts": [ "b:27017", "c:27017", "d:27017", "e:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": { "b:27017": { "setName": "rs", "type": "RSSecondary" }, "c:27017": { "setName": "rs", "type": "RSSecondary" }, "d:27017": { "setName": "rs", "type": "RSPrimary" }, "e:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "c:27017", { "hosts": [ "a:27017", "b:27017", "c:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "rs" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/equal_electionids.json000066400000000000000000000037171264720626300313140ustar00rootroot00000000000000{ "description": "New primary with equal electionId", "phases": [ { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": null, "setVersion": null, "type": "Unknown" }, "b:27017": { "electionId": { "$oid": "000000000000000000000001" }, "setName": "rs", "setVersion": 1, "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "electionId": { "$oid": "000000000000000000000001" }, "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ], [ "b:27017", { "electionId": { "$oid": "000000000000000000000001" }, "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/ghost_discovered.json000066400000000000000000000015401264720626300311460ustar00rootroot00000000000000{ "description": "Ghost discovered", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" }, "b:27017": { "setName": null, "type": "RSGhost" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "b:27017", { "ismaster": false, "isreplicaset": true, "ok": 1 } ] ] } ], "uri": "mongodb://a,b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/hosts_differ_from_seeds.json000066400000000000000000000014741264720626300325060ustar00rootroot00000000000000{ "description": "Host list differs from seeds", "phases": [ { "outcome": { "servers": { "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/member_reconfig.json000066400000000000000000000032771264720626300307470ustar00rootroot00000000000000{ "description": "Member removed by reconfig", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a,b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/member_standalone.json000066400000000000000000000025411264720626300312740ustar00rootroot00000000000000{ "description": "Member brought up as standalone", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" } }, "setName": null, "topologyType": "Unknown" }, "responses": [ [ "b:27017", { "ismaster": true, "ok": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a,b" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/new_primary.json000066400000000000000000000035451264720626300301560ustar00rootroot00000000000000{ "description": "New primary", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" }, "b:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a,b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/new_primary_new_electionid.json000066400000000000000000000076361264720626300332330ustar00rootroot00000000000000{ "description": "New primary with greater setVersion and electionId", "phases": [ { "outcome": { "servers": { "a:27017": { "electionId": { "$oid": "000000000000000000000001" }, "setName": "rs", "setVersion": 1, "type": "RSPrimary" }, "b:27017": { "electionId": null, "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "electionId": { "$oid": "000000000000000000000001" }, "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": null, "type": "Unknown" }, "b:27017": { "electionId": { "$oid": "000000000000000000000002" }, "setName": "rs", "setVersion": 1, "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "b:27017", { "electionId": { "$oid": "000000000000000000000002" }, "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": null, "type": "Unknown" }, "b:27017": { "electionId": { "$oid": "000000000000000000000002" }, "setName": "rs", "setVersion": 1, "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "electionId": { "$oid": "000000000000000000000001" }, "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/new_primary_wrong_set_name.json000066400000000000000000000033041264720626300332360ustar00rootroot00000000000000{ "description": "New primary with wrong setName", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "wrong" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/non_rs_member.json000066400000000000000000000012061264720626300304370ustar00rootroot00000000000000{ "description": "Non replicaSet member responds", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "b:27017", { "ok": 1 } ] ] } ], "uri": "mongodb://a,b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/normalize_case.json000066400000000000000000000024541264720626300306130ustar00rootroot00000000000000{ "description": "Replica set case normalization", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": null, "type": "Unknown" }, "c:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "arbiters": [ "C:27017" ], "hosts": [ "A:27017" ], "ismaster": true, "ok": 1, "passives": [ "B:27017" ], "setName": "rs" } ] ] } ], "uri": "mongodb://A/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/null_election_id.json000066400000000000000000000130301264720626300311200ustar00rootroot00000000000000{ "description": "Primaries with and without electionIds", "phases": [ { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": "rs", "setVersion": 1, "type": "RSPrimary" }, "b:27017": { "electionId": null, "setName": null, "type": "Unknown" }, "c:27017": { "electionId": null, "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017", "c:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": null, "type": "Unknown" }, "b:27017": { "electionId": { "$oid": "000000000000000000000002" }, "setName": "rs", "setVersion": 1, "type": "RSPrimary" }, "c:27017": { "electionId": null, "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "b:27017", { "electionId": { "$oid": "000000000000000000000002" }, "hosts": [ "a:27017", "b:27017", "c:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": "rs", "setVersion": 1, "type": "RSPrimary" }, "b:27017": { "electionId": null, "setName": null, "type": "Unknown" }, "c:27017": { "electionId": null, "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017", "c:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": "rs", "setVersion": 1, "type": "RSPrimary" }, "b:27017": { "electionId": null, "setName": null, "type": "Unknown" }, "c:27017": { "electionId": null, "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "c:27017", { "electionId": { "$oid": "000000000000000000000001" }, "hosts": [ "a:27017", "b:27017", "c:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/primary_becomes_standalone.json000066400000000000000000000022561264720626300332100ustar00rootroot00000000000000{ "description": "Primary becomes standalone", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": {}, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "ok": 1 } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/primary_changes_set_name.json000066400000000000000000000025501264720626300326430ustar00rootroot00000000000000{ "description": "Primary changes setName", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": {}, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "wrong" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/primary_disconnect.json000066400000000000000000000024241264720626300315110ustar00rootroot00000000000000{ "description": "Disconnected from primary", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", {} ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/primary_disconnect_electionid.json000066400000000000000000000142671264720626300337200ustar00rootroot00000000000000{ "description": "Disconnected from primary, reject primary with stale electionId", "phases": [ { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": null, "type": "Unknown" }, "b:27017": { "electionId": { "$oid": "000000000000000000000002" }, "setName": "rs", "setVersion": 1, "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "electionId": { "$oid": "000000000000000000000001" }, "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ], [ "b:27017", { "electionId": { "$oid": "000000000000000000000002" }, "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": null, "type": "Unknown" }, "b:27017": { "electionId": null, "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "b:27017", {} ] ] }, { "outcome": { "servers": { "a:27017": { "electionId": null, "setName": null, "type": "Unknown" }, "b:27017": { "electionId": null, "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "electionId": { "$oid": "000000000000000000000001" }, "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "electionId": { "$oid": "000000000000000000000003" }, "setName": "rs", "setVersion": 1, "type": "RSPrimary" }, "b:27017": { "electionId": null, "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "electionId": { "$oid": "000000000000000000000003" }, "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs", "setVersion": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "electionId": { "$oid": "000000000000000000000003" }, "setName": "rs", "setVersion": 1, "type": "RSPrimary" }, "b:27017": { "setName": "rs", "setVersion": 2, "type": "RSSecondary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "rs", "setVersion": 2 } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/primary_mismatched_me.json000066400000000000000000000020521264720626300321540ustar00rootroot00000000000000{ "description": "Primary mismatched me", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "localhost:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "me": "a:27017", "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://localhost:27017/?replicaSet=rs" } primary_to_no_primary_mismatched_me.json000066400000000000000000000037201264720626300350410ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs{ "description": "Primary to no primary with mismatched me", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "me": "a:27017", "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": { "c:27017": { "setName": null, "type": "Unknown" }, "d:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "c:27017", "d:27017" ], "ismaster": true, "me": "c:27017", "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/primary_wrong_set_name.json000066400000000000000000000012341264720626300323650ustar00rootroot00000000000000{ "description": "Primary wrong setName", "phases": [ { "outcome": { "servers": {}, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "wrong" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/response_from_removed.json000066400000000000000000000031411264720626300322140ustar00rootroot00000000000000{ "description": "Response from removed server", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "rs" } ] ] } ], "uri": "mongodb://a,b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/rsother_discovered.json000066400000000000000000000033731264720626300315160ustar00rootroot00000000000000{ "description": "RSOther discovered", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSOther" }, "b:27017": { "setName": "rs", "type": "RSOther" }, "c:27017": { "setName": null, "type": "Unknown" }, "d:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "hidden": true, "hosts": [ "c:27017", "d:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "rs" } ], [ "b:27017", { "hosts": [ "c:27017", "d:27017" ], "ismaster": false, "ok": 1, "secondary": false, "setName": "rs" } ] ] } ], "uri": "mongodb://a,b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/sec_not_auth.json000066400000000000000000000026501264720626300302710ustar00rootroot00000000000000{ "description": "Secondary's host list is not authoritative", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": "rs", "type": "RSSecondary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ], [ "b:27017", { "hosts": [ "b:27017", "c:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "rs" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/secondary_mismatched_me.json000066400000000000000000000020551264720626300324630ustar00rootroot00000000000000{ "description": "Secondary mismatched me", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "localhost:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": false, "me": "a:27017", "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://localhost:27017/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/secondary_wrong_set_name.json000066400000000000000000000013131264720626300326670ustar00rootroot00000000000000{ "description": "Secondary wrong setName", "phases": [ { "outcome": { "servers": {}, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "wrong" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } secondary_wrong_set_name_with_primary.json000066400000000000000000000034411264720626300354120ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs{ "description": "Secondary wrong setName with primary", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "wrong" } ] ] } ], "uri": "mongodb://a,b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/stepdown_change_set_name.json000066400000000000000000000026541264720626300326450ustar00rootroot00000000000000{ "description": "Primary becomes a secondary with wrong setName", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] }, { "outcome": { "servers": {}, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "wrong" } ] ] } ], "uri": "mongodb://a/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/unexpected_mongos.json000066400000000000000000000010621264720626300313400ustar00rootroot00000000000000{ "description": "Unexpected mongos", "phases": [ { "outcome": { "servers": {}, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "b:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ] ] } ], "uri": "mongodb://b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/rs/wrong_set_name.json000066400000000000000000000016071264720626300306260ustar00rootroot00000000000000{ "description": "Wrong setName", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "b:27017", "c:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "wrong" } ] ] } ], "uri": "mongodb://a,b/?replicaSet=rs" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/sharded/000077500000000000000000000000001264720626300257065ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/sharded/mongos_disconnect.json000066400000000000000000000045421264720626300323210ustar00rootroot00000000000000{ "description": "Mongos disconnect", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Mongos" }, "b:27017": { "setName": null, "type": "Mongos" } }, "setName": null, "topologyType": "Sharded" }, "responses": [ [ "a:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ], [ "b:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ] ] }, { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" }, "b:27017": { "setName": null, "type": "Mongos" } }, "setName": null, "topologyType": "Sharded" }, "responses": [ [ "a:27017", {} ] ] }, { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Mongos" }, "b:27017": { "setName": null, "type": "Mongos" } }, "setName": null, "topologyType": "Sharded" }, "responses": [ [ "a:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ] ] } ], "uri": "mongodb://a,b" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/sharded/multiple_mongoses.json000066400000000000000000000020511264720626300323440ustar00rootroot00000000000000{ "description": "Multiple mongoses", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Mongos" }, "b:27017": { "setName": null, "type": "Mongos" } }, "setName": null, "topologyType": "Sharded" }, "responses": [ [ "a:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ], [ "b:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ] ] } ], "uri": "mongodb://a,b" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/sharded/non_mongos_removed.json000066400000000000000000000020231264720626300324730ustar00rootroot00000000000000{ "description": "Non-Mongos server in sharded cluster", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Mongos" } }, "setName": null, "topologyType": "Sharded" }, "responses": [ [ "a:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ], [ "b:27017", { "hosts": [ "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a,b" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/sharded/normalize_uri_case.json000066400000000000000000000011171264720626300324530ustar00rootroot00000000000000{ "description": "Normalize URI case", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" }, "b:27017": { "setName": null, "type": "Unknown" } }, "setName": null, "topologyType": "Unknown" }, "responses": [] } ], "uri": "mongodb://A,B" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/000077500000000000000000000000001264720626300255555ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/direct_connection_external_ip.json000066400000000000000000000014641264720626300345400ustar00rootroot00000000000000{ "description": "Direct connection to RSPrimary via external IP", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": null, "topologyType": "Single" }, "responses": [ [ "a:27017", { "hosts": [ "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/direct_connection_mongos.json000066400000000000000000000012611264720626300335230ustar00rootroot00000000000000{ "description": "Connect to mongos", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Mongos" } }, "setName": null, "topologyType": "Single" }, "responses": [ [ "a:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ] ] } ], "uri": "mongodb://a" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/direct_connection_rsarbiter.json000066400000000000000000000015111264720626300342140ustar00rootroot00000000000000{ "description": "Connect to RSArbiter", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSArbiter" } }, "setName": null, "topologyType": "Single" }, "responses": [ [ "a:27017", { "arbiterOnly": true, "hosts": [ "a:27017" ], "ismaster": false, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/direct_connection_rsprimary.json000066400000000000000000000014321264720626300342510ustar00rootroot00000000000000{ "description": "Connect to RSPrimary", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": null, "topologyType": "Single" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ] ] } ], "uri": "mongodb://a" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/direct_connection_rssecondary.json000066400000000000000000000015131264720626300345550ustar00rootroot00000000000000{ "description": "Connect to RSSecondary", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSSecondary" } }, "setName": null, "topologyType": "Single" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "rs" } ] ] } ], "uri": "mongodb://a" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/direct_connection_slave.json000066400000000000000000000012231264720626300333310ustar00rootroot00000000000000{ "description": "Direct connection to slave", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Standalone" } }, "setName": null, "topologyType": "Single" }, "responses": [ [ "a:27017", { "ismaster": false, "ok": 1 } ] ] } ], "uri": "mongodb://a" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/direct_connection_standalone.json000066400000000000000000000012151264720626300343500ustar00rootroot00000000000000{ "description": "Connect to standalone", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Standalone" } }, "setName": null, "topologyType": "Single" }, "responses": [ [ "a:27017", { "ismaster": true, "ok": 1 } ] ] } ], "uri": "mongodb://a" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/not_ok_response.json000066400000000000000000000015231264720626300316600ustar00rootroot00000000000000{ "description": "Handle a not-ok ismaster response", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" } }, "setName": null, "topologyType": "Single" }, "responses": [ [ "a:27017", { "ismaster": true, "ok": 1 } ], [ "a:27017", { "ismaster": true, "ok": 0 } ] ] } ], "uri": "mongodb://a" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/standalone_removed.json000066400000000000000000000012451264720626300323230ustar00rootroot00000000000000{ "description": "Standalone removed from multi-server topology", "phases": [ { "outcome": { "servers": { "b:27017": { "setName": null, "type": "Unknown" } }, "setName": null, "topologyType": "Unknown" }, "responses": [ [ "a:27017", { "ismaster": true, "ok": 1 } ] ] } ], "uri": "mongodb://a,b" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/single/unavailable_seed.json000066400000000000000000000010451264720626300317330ustar00rootroot00000000000000{ "description": "Unavailable seed", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": null, "type": "Unknown" } }, "setName": null, "topologyType": "Single" }, "responses": [ [ "a:27017", {} ] ] } ], "uri": "mongodb://a" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/supplemental/000077500000000000000000000000001264720626300270055ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/supplemental/discover_rs_name.json000066400000000000000000000023171264720626300332250ustar00rootroot00000000000000{ "description": "Discover replica set name", "phases": [ { "outcome": { "servers": { "a:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "a:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ], [ "b:27017", { "hosts": [ "a:27017", "b:27017" ], "ismaster": true, "ok": 1, "setName": "wrong" } ] ] } ], "uri": "mongodb://a,b" } libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/supplemental/discover_rs_name.yml000066400000000000000000000014571264720626300330610ustar00rootroot00000000000000description: "Discover replica set name" uri: "mongodb://a,b" # No replicaSet= option phases: [ { responses: [ ["a:27017", { ok: 1, ismaster: true, hosts: ["a:27017", "b:27017"], setName: "rs" }], ["b:27017", { ok: 1, ismaster: true, hosts: ["a:27017", "b:27017"], setName: "wrong" }] ], outcome: { servers: { "a:27017": { type: "RSPrimary", setName: "rs" } }, topologyType: "ReplicaSetWithPrimary", setName: "rs" } } ] discover_rs_name_from_primary.json000066400000000000000000000020461264720626300357330ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/supplemental{ "description": "Discover replica set name from primary", "phases": [ { "outcome": { "servers": { "b:27017": { "setName": "rs", "type": "RSPrimary" } }, "setName": "rs", "topologyType": "ReplicaSetWithPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "b:27017" ], "ismaster": true, "ok": 1, "setName": "rs" } ], [ "a:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ] ] } ], "uri": "mongodb://a,b" } discover_rs_name_from_primary.yml000066400000000000000000000013751264720626300355670ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/supplementaldescription: "Discover replica set name from primary" uri: "mongodb://a,b" # No replicaSet= option phases: [ { responses: [ ["b:27017", { ok: 1, ismaster: true, hosts: ["b:27017"], setName: "rs" }], ["a:27017", { ok: 1, ismaster: true, msg: "isdbgrid" }] ], outcome: { servers: { "b:27017": { type: "RSPrimary", setName: "rs" } }, topologyType: "ReplicaSetWithPrimary", setName: "rs" } } ] discover_rs_name_from_secondary.json000066400000000000000000000021251264720626300362350ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/supplemental{ "description": "Discover replica set name from secondary", "phases": [ { "outcome": { "servers": { "b:27017": { "setName": "rs", "type": "RSSecondary" } }, "setName": "rs", "topologyType": "ReplicaSetNoPrimary" }, "responses": [ [ "b:27017", { "hosts": [ "b:27017" ], "ismaster": false, "ok": 1, "secondary": true, "setName": "rs" } ], [ "a:27017", { "ismaster": true, "msg": "isdbgrid", "ok": 1 } ] ] } ], "uri": "mongodb://a,b" } discover_rs_name_from_secondary.yml000066400000000000000000000014451264720626300360710ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_discovery_and_monitoring/supplementaldescription: "Discover replica set name from secondary" uri: "mongodb://a,b" # No replicaSet= option phases: [ { responses: [ ["b:27017", { ok: 1, ismaster: false, secondary: true, hosts: ["b:27017"], setName: "rs" }], ["a:27017", { ok: 1, ismaster: true, msg: "isdbgrid" }] ], outcome: { servers: { "b:27017": { type: "RSSecondary", setName: "rs" } }, topologyType: "ReplicaSetNoPrimary", setName: "rs" } } ] libmongoc-1.3.1/tests/json/server_selection/000077500000000000000000000000001264720626300211635ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/rtt/000077500000000000000000000000001264720626300217745ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/rtt/first_value.json000066400000000000000000000001141264720626300252060ustar00rootroot00000000000000{ "avg_rtt_ms": "NULL", "new_avg_rtt": 10, "new_rtt_ms": 10 } libmongoc-1.3.1/tests/json/server_selection/rtt/first_value_zero.json000066400000000000000000000001121264720626300262430ustar00rootroot00000000000000{ "avg_rtt_ms": "NULL", "new_avg_rtt": 0, "new_rtt_ms": 0 } libmongoc-1.3.1/tests/json/server_selection/rtt/value_test_1.json000066400000000000000000000001071264720626300252600ustar00rootroot00000000000000{ "avg_rtt_ms": 0, "new_avg_rtt": 1.0, "new_rtt_ms": 5 } libmongoc-1.3.1/tests/json/server_selection/rtt/value_test_2.json000066400000000000000000000001131264720626300252560ustar00rootroot00000000000000{ "avg_rtt_ms": 3.1, "new_avg_rtt": 9.68, "new_rtt_ms": 36 } libmongoc-1.3.1/tests/json/server_selection/rtt/value_test_3.json000066400000000000000000000001161264720626300252620ustar00rootroot00000000000000{ "avg_rtt_ms": 9.12, "new_avg_rtt": 9.12, "new_rtt_ms": 9.12 } libmongoc-1.3.1/tests/json/server_selection/rtt/value_test_4.json000066400000000000000000000001141264720626300252610ustar00rootroot00000000000000{ "avg_rtt_ms": 1, "new_avg_rtt": 200.8, "new_rtt_ms": 1000 } libmongoc-1.3.1/tests/json/server_selection/rtt/value_test_5.json000066400000000000000000000001131264720626300252610ustar00rootroot00000000000000{ "avg_rtt_ms": 0, "new_avg_rtt": 0.05, "new_rtt_ms": 0.25 } libmongoc-1.3.1/tests/json/server_selection/server_selection/000077500000000000000000000000001264720626300245365ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/000077500000000000000000000000001264720626300304325ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read/000077500000000000000000000000001264720626300313455ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read/Nearest.json000066400000000000000000000051071264720626300336440ustar00rootroot00000000000000{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "in_latency_window": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "operation": "read", "read_preference": { "mode": "Nearest", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } Nearest_non_matching.json000066400000000000000000000026351264720626300363140ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [], "in_latency_window": [], "operation": "read", "read_preference": { "mode": "Nearest", "tags": [ { "data_center": "sf" } ] }, "suitable_servers": [], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read/Primary.json000066400000000000000000000016171264720626300336700ustar00rootroot00000000000000{ "candidate_servers": [], "eligible_servers": [], "in_latency_window": [], "operation": "read", "read_preference": { "mode": "Primary", "tags": [ {} ] }, "suitable_servers": [], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } PrimaryPreferred.json000066400000000000000000000050361264720626300354470ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "in_latency_window": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "operation": "read", "read_preference": { "mode": "PrimaryPreferred", "tags": [ {} ] }, "suitable_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } PrimaryPreferred_non_matching.json000066400000000000000000000026461264720626300401770ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [], "in_latency_window": [], "operation": "read", "read_preference": { "mode": "PrimaryPreferred", "tags": [ { "data_center": "sf" } ] }, "suitable_servers": [], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read/Secondary.json000066400000000000000000000051111264720626300341650ustar00rootroot00000000000000{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "in_latency_window": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "operation": "read", "read_preference": { "mode": "Secondary", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } SecondaryPreferred.json000066400000000000000000000051221264720626300357470ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "in_latency_window": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "operation": "read", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } SecondaryPreferred_non_matching.json000066400000000000000000000026501264720626300404760ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [], "in_latency_window": [], "operation": "read", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "sf" } ] }, "suitable_servers": [], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } Secondary_non_matching.json000066400000000000000000000026371264720626300366440ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [], "in_latency_window": [], "operation": "read", "read_preference": { "mode": "Secondary", "tags": [ { "data_center": "sf" } ] }, "suitable_servers": [], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/write/000077500000000000000000000000001264720626300315645ustar00rootroot00000000000000SecondaryPreferred.json000066400000000000000000000017151264720626300361720ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetNoPrimary/write{ "candidate_servers": [], "eligible_servers": [], "in_latency_window": [], "operation": "write", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "type": "ReplicaSetNoPrimary" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/000077500000000000000000000000001264720626300307715ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read/000077500000000000000000000000001264720626300317045ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read/Nearest.json000066400000000000000000000070351264720626300342050ustar00rootroot00000000000000{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "eligible_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "in_latency_window": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "operation": "read", "read_preference": { "mode": "Nearest", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } Nearest_non_matching.json000066400000000000000000000036351264720626300366540ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "eligible_servers": [], "in_latency_window": [], "operation": "read", "read_preference": { "mode": "Nearest", "tags": [ { "data_center": "sf" } ] }, "suitable_servers": [], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read/Primary.json000066400000000000000000000041341264720626300342240ustar00rootroot00000000000000{ "candidate_servers": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "eligible_servers": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "in_latency_window": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "operation": "read", "read_preference": { "mode": "Primary", "tags": [ {} ] }, "suitable_servers": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } PrimaryPreferred.json000066400000000000000000000060311264720626300360020ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "eligible_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "in_latency_window": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "operation": "read", "read_preference": { "mode": "PrimaryPreferred", "tags": [ {} ] }, "suitable_servers": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } PrimaryPreferred_non_matching.json000066400000000000000000000046021264720626300405300ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "eligible_servers": [], "in_latency_window": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "operation": "read", "read_preference": { "mode": "PrimaryPreferred", "tags": [ { "data_center": "sf" } ] }, "suitable_servers": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } Secondary.json000066400000000000000000000055361264720626300344600ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "in_latency_window": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "operation": "read", "read_preference": { "mode": "Secondary", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } SecondaryPreferred.json000066400000000000000000000064751264720626300363220ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "eligible_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "in_latency_window": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "operation": "read", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } SecondaryPreferred_non_matching.json000066400000000000000000000046041264720626300410360ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "eligible_servers": [], "in_latency_window": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "operation": "read", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "sf" } ] }, "suitable_servers": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } Secondary_non_matching.json000066400000000000000000000032641264720626300372000ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/read{ "candidate_servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" } ], "eligible_servers": [], "in_latency_window": [], "operation": "read", "read_preference": { "mode": "Secondary", "tags": [ { "data_center": "sf" } ] }, "suitable_servers": [], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/write/000077500000000000000000000000001264720626300321235ustar00rootroot00000000000000SecondaryPreferred.json000066400000000000000000000042321264720626300365260ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/ReplicaSetWithPrimary/write{ "candidate_servers": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "eligible_servers": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "in_latency_window": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "operation": "write", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "topology_description": { "servers": [ { "address": "b:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "c:27017", "avg_rtt_ms": 100, "tags": [ { "data_center": "nyc" } ], "type": "RSSecondary" }, { "address": "a:27017", "avg_rtt_ms": 26, "tags": [ { "data_center": "nyc" } ], "type": "RSPrimary" } ], "type": "ReplicaSetWithPrimary" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/Sharded/000077500000000000000000000000001264720626300261105ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/Sharded/read/000077500000000000000000000000001264720626300270235ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/Sharded/read/SecondaryPreferred.json000066400000000000000000000050211264720626300335020ustar00rootroot00000000000000{ "candidate_servers": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" }, { "address": "h:27017", "avg_rtt_ms": 35, "tags": [ { "data_center": "dc" } ], "type": "Mongos" } ], "eligible_servers": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" }, { "address": "h:27017", "avg_rtt_ms": 35, "tags": [ { "data_center": "dc" } ], "type": "Mongos" } ], "in_latency_window": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" } ], "operation": "read", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" }, { "address": "h:27017", "avg_rtt_ms": 35, "tags": [ { "data_center": "dc" } ], "type": "Mongos" } ], "topology_description": { "servers": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" }, { "address": "h:27017", "avg_rtt_ms": 35, "tags": [ { "data_center": "dc" } ], "type": "Mongos" } ], "type": "Sharded" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/Sharded/write/000077500000000000000000000000001264720626300272425ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/Sharded/write/SecondaryPreferred.json000066400000000000000000000050221264720626300337220ustar00rootroot00000000000000{ "candidate_servers": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" }, { "address": "h:27017", "avg_rtt_ms": 35, "tags": [ { "data_center": "dc" } ], "type": "Mongos" } ], "eligible_servers": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" }, { "address": "h:27017", "avg_rtt_ms": 35, "tags": [ { "data_center": "dc" } ], "type": "Mongos" } ], "in_latency_window": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" } ], "operation": "write", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" }, { "address": "h:27017", "avg_rtt_ms": 35, "tags": [ { "data_center": "dc" } ], "type": "Mongos" } ], "topology_description": { "servers": [ { "address": "g:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "nyc" } ], "type": "Mongos" }, { "address": "h:27017", "avg_rtt_ms": 35, "tags": [ { "data_center": "dc" } ], "type": "Mongos" } ], "type": "Sharded" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/Single/000077500000000000000000000000001264720626300257575ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/Single/read/000077500000000000000000000000001264720626300266725ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/Single/read/SecondaryPreferred.json000066400000000000000000000031331264720626300333530ustar00rootroot00000000000000{ "candidate_servers": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "eligible_servers": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "in_latency_window": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "operation": "read", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "topology_description": { "servers": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "type": "Single" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/Single/write/000077500000000000000000000000001264720626300271115ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/Single/write/SecondaryPreferred.json000066400000000000000000000031341264720626300335730ustar00rootroot00000000000000{ "candidate_servers": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "eligible_servers": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "in_latency_window": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "operation": "write", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "topology_description": { "servers": [ { "address": "a:27017", "avg_rtt_ms": 5, "tags": [ { "data_center": "dc" } ], "type": "Standalone" } ], "type": "Single" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/Unknown/000077500000000000000000000000001264720626300261755ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/Unknown/read/000077500000000000000000000000001264720626300271105ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/Unknown/read/SecondaryPreferred.json000066400000000000000000000006171264720626300335750ustar00rootroot00000000000000{ "candidate_servers": [], "eligible_servers": [], "in_latency_window": [], "operation": "read", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [], "topology_description": { "servers": [], "type": "Unknown" } } libmongoc-1.3.1/tests/json/server_selection/server_selection/Unknown/write/000077500000000000000000000000001264720626300273275ustar00rootroot00000000000000libmongoc-1.3.1/tests/json/server_selection/server_selection/Unknown/write/SecondaryPreferred.json000066400000000000000000000006201264720626300340060ustar00rootroot00000000000000{ "candidate_servers": [], "eligible_servers": [], "in_latency_window": [], "operation": "write", "read_preference": { "mode": "SecondaryPreferred", "tags": [ { "data_center": "nyc" } ] }, "suitable_servers": [], "topology_description": { "servers": [], "type": "Unknown" } } libmongoc-1.3.1/tests/make_ca.pl000077500000000000000000000063711264720626300165660ustar00rootroot00000000000000#!/usr/bin/perl -w # Simple script that uses openssl and c_rehash to set up a ca to generate certs # for test-mongoc-stream-tls use strict; use File::Copy; my $subj = "/C=US/ST=NY/L=New York/O=MongoDB Inc./OU=C Driver/SAN=foo.com/CN="; my ($ca_dir, $conf) = @ARGV; my @dirs = ( $ca_dir, "$ca_dir/build", "$ca_dir/verify", "$ca_dir/ca.db.certs", "$ca_dir/keys", "$ca_dir/crl", ); system("rm", "-rf", "$ca_dir"); # Create the relevant directory structure and files for a CA { for my $dir (@dirs) { mkdir $dir or die "Couldn't create dir: $!"; } set_file("$ca_dir/ca.db.index", ""); set_file("$ca_dir/ca.db.serial", "01\n"); set_file("$ca_dir/ca.db.rand", "151\n"); } # generate the root key and cert { openssl ("genrsa", "-out", "$ca_dir/signing-ca.key", "1024"); openssl ("req", "-new", "-x509", "-days", 365, "-key", "$ca_dir/signing-ca.key", "-out", "$ca_dir/signing-ca.crt", "-config", $conf, "-subj", "${subj}mongo_root"); copy ("$ca_dir/signing-ca.crt", "$ca_dir/verify/mongo_root.pem"); } # generate a simple password less cert { openssl("req", "-nodes", "-newkey", "rsa:1024", req_args("mongodb.com")); openssl("ca", ca_args("mongodb.com")); dist_files("mongodb.com"); } # generate a simple passworded cert { openssl ("req", "-passout", "pass:testpass", "-newkey", "rsa:1024", req_args ("pass.mongodb.com")); openssl ("ca", ca_args ("pass.mongodb.com")); dist_files ("pass.mongodb.com"); } # generate a cert and revoke it to test crls { openssl ("req", "-nodes", "-newkey", "rsa:1024", req_args ("rev.mongodb.com")); openssl ("ca", ca_args ("rev.mongodb.com")); dist_files ("rev.mongodb.com"); openssl ("ca", "-config", $conf, "-revoke", "$ca_dir/verify/rev.mongodb.com.pem"); openssl ("ca", "-config", $conf, "-gencrl", "-out", "$ca_dir/crl/root.crl.pem"); } # generate a cert with some alt names including a wild card { openssl ("req", "-nodes", "-newkey", "rsa:1024", req_args ("alt.mongodb.com")); openssl ("ca", "-extensions", "v3_req", ca_args ("alt.mongodb.com")); dist_files ("alt.mongodb.com"); } # generate a cert for localhost { openssl ("req", "-nodes", "-newkey", "rsa:1024", req_args ("127.0.0.1")); openssl ("ca", ca_args ("127.0.0.1")); dist_files ("127.0.0.1"); } # generate the hash directory structure ssl needs system("c_rehash", "$ca_dir/verify") and die "failed: $?"; sub dist_files { my ($name) = @_; system("cat '$ca_dir/build/$name.key' '$ca_dir/build/$name.crt' > '$ca_dir/keys/$name.pem'") and die "terribly: $?"; copy("$ca_dir/build/$name.crt", "$ca_dir/verify/$name.pem"); } sub ca_args { my $name = $_[0]; return "-batch", "-config", $conf, "-out", "$ca_dir/build/$name.crt", "-in", "$ca_dir/build/$name.req", ; } sub req_args { my $name = $_[0]; return ( "-keyout", "$ca_dir/build/$name.key", "-out", "$ca_dir/build/$name.req", "-config", $conf, "-subj", "$subj$name", ); } sub openssl { my @args = @_; system("openssl", @args) and die "failed: $?" } sub set_file { my ($name, $contents) = @_; open my $file, "> $name" or die "Couldn't open $name: $!"; print $file $contents; close $file; } libmongoc-1.3.1/tests/mock_server/000077500000000000000000000000001264720626300171565ustar00rootroot00000000000000libmongoc-1.3.1/tests/mock_server/future-functions.c000066400000000000000000000624611264720626300226530ustar00rootroot00000000000000/************************************************** * * Generated by build/generate-future-functions.py. * * DO NOT EDIT THIS FILE. * *************************************************/ /* * Define two sets of functions: background functions and future functions. * A background function like background_mongoc_cursor_next runs a driver * operation on a thread. * A future function like future_mongoc_cursor_next launches the background * operation and returns a future_t that will resolve when the operation * finishes. * * These are used with mock_server_t so you can run the driver on a thread while * controlling the server from the main thread. */ #include "mongoc-topology-private.h" #include "future-functions.h" static void * background_mongoc_bulk_operation_execute (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_uint32_t_type; future_value_set_uint32_t ( &return_value, mongoc_bulk_operation_execute ( future_value_get_mongoc_bulk_operation_ptr (future_get_param (future, 0)), future_value_get_bson_ptr (future_get_param (future, 1)), future_value_get_bson_error_ptr (future_get_param (future, 2)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_client_command_simple (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_bool_type; future_value_set_bool ( &return_value, mongoc_client_command_simple ( future_value_get_mongoc_client_ptr (future_get_param (future, 0)), future_value_get_const_char_ptr (future_get_param (future, 1)), future_value_get_const_bson_ptr (future_get_param (future, 2)), future_value_get_const_mongoc_read_prefs_ptr (future_get_param (future, 3)), future_value_get_bson_ptr (future_get_param (future, 4)), future_value_get_bson_error_ptr (future_get_param (future, 5)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_client_kill_cursor (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_void_type; mongoc_client_kill_cursor ( future_value_get_mongoc_client_ptr (future_get_param (future, 0)), future_value_get_int64_t (future_get_param (future, 1))); future_resolve (future, return_value); return NULL; } static void * background_mongoc_collection_aggregate (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_mongoc_cursor_ptr_type; future_value_set_mongoc_cursor_ptr ( &return_value, mongoc_collection_aggregate ( future_value_get_mongoc_collection_ptr (future_get_param (future, 0)), future_value_get_mongoc_query_flags_t (future_get_param (future, 1)), future_value_get_const_bson_ptr (future_get_param (future, 2)), future_value_get_const_bson_ptr (future_get_param (future, 3)), future_value_get_const_mongoc_read_prefs_ptr (future_get_param (future, 4)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_collection_count (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_int64_t_type; future_value_set_int64_t ( &return_value, mongoc_collection_count ( future_value_get_mongoc_collection_ptr (future_get_param (future, 0)), future_value_get_mongoc_query_flags_t (future_get_param (future, 1)), future_value_get_const_bson_ptr (future_get_param (future, 2)), future_value_get_int64_t (future_get_param (future, 3)), future_value_get_int64_t (future_get_param (future, 4)), future_value_get_const_mongoc_read_prefs_ptr (future_get_param (future, 5)), future_value_get_bson_error_ptr (future_get_param (future, 6)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_collection_find_and_modify_with_opts (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_bool_type; future_value_set_bool ( &return_value, mongoc_collection_find_and_modify_with_opts ( future_value_get_mongoc_collection_ptr (future_get_param (future, 0)), future_value_get_const_bson_ptr (future_get_param (future, 1)), future_value_get_const_mongoc_find_and_modify_opts_ptr (future_get_param (future, 2)), future_value_get_bson_ptr (future_get_param (future, 3)), future_value_get_bson_error_ptr (future_get_param (future, 4)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_collection_find_and_modify (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_bool_type; future_value_set_bool ( &return_value, mongoc_collection_find_and_modify ( future_value_get_mongoc_collection_ptr (future_get_param (future, 0)), future_value_get_const_bson_ptr (future_get_param (future, 1)), future_value_get_const_bson_ptr (future_get_param (future, 2)), future_value_get_const_bson_ptr (future_get_param (future, 3)), future_value_get_const_bson_ptr (future_get_param (future, 4)), future_value_get_bool (future_get_param (future, 5)), future_value_get_bool (future_get_param (future, 6)), future_value_get_bool (future_get_param (future, 7)), future_value_get_bson_ptr (future_get_param (future, 8)), future_value_get_bson_error_ptr (future_get_param (future, 9)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_collection_insert (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_bool_type; future_value_set_bool ( &return_value, mongoc_collection_insert ( future_value_get_mongoc_collection_ptr (future_get_param (future, 0)), future_value_get_mongoc_insert_flags_t (future_get_param (future, 1)), future_value_get_const_bson_ptr (future_get_param (future, 2)), future_value_get_const_mongoc_write_concern_ptr (future_get_param (future, 3)), future_value_get_bson_error_ptr (future_get_param (future, 4)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_collection_insert_bulk (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_bool_type; future_value_set_bool ( &return_value, mongoc_collection_insert_bulk ( future_value_get_mongoc_collection_ptr (future_get_param (future, 0)), future_value_get_mongoc_insert_flags_t (future_get_param (future, 1)), future_value_get_const_bson_ptr_ptr (future_get_param (future, 2)), future_value_get_uint32_t (future_get_param (future, 3)), future_value_get_const_mongoc_write_concern_ptr (future_get_param (future, 4)), future_value_get_bson_error_ptr (future_get_param (future, 5)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_cursor_destroy (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_void_type; mongoc_cursor_destroy ( future_value_get_mongoc_cursor_ptr (future_get_param (future, 0))); future_resolve (future, return_value); return NULL; } static void * background_mongoc_cursor_next (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_bool_type; future_value_set_bool ( &return_value, mongoc_cursor_next ( future_value_get_mongoc_cursor_ptr (future_get_param (future, 0)), future_value_get_const_bson_ptr_ptr (future_get_param (future, 1)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_client_get_database_names (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_char_ptr_ptr_type; future_value_set_char_ptr_ptr ( &return_value, mongoc_client_get_database_names ( future_value_get_mongoc_client_ptr (future_get_param (future, 0)), future_value_get_bson_error_ptr (future_get_param (future, 1)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_database_get_collection_names (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_char_ptr_ptr_type; future_value_set_char_ptr_ptr ( &return_value, mongoc_database_get_collection_names ( future_value_get_mongoc_database_ptr (future_get_param (future, 0)), future_value_get_bson_error_ptr (future_get_param (future, 1)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_gridfs_file_readv (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_ssize_t_type; future_value_set_ssize_t ( &return_value, mongoc_gridfs_file_readv ( future_value_get_mongoc_gridfs_file_ptr (future_get_param (future, 0)), future_value_get_mongoc_iovec_ptr (future_get_param (future, 1)), future_value_get_size_t (future_get_param (future, 2)), future_value_get_size_t (future_get_param (future, 3)), future_value_get_uint32_t (future_get_param (future, 4)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_gridfs_file_seek (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_int_type; future_value_set_int ( &return_value, mongoc_gridfs_file_seek ( future_value_get_mongoc_gridfs_file_ptr (future_get_param (future, 0)), future_value_get_int64_t (future_get_param (future, 1)), future_value_get_int (future_get_param (future, 2)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_gridfs_file_writev (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_ssize_t_type; future_value_set_ssize_t ( &return_value, mongoc_gridfs_file_writev ( future_value_get_mongoc_gridfs_file_ptr (future_get_param (future, 0)), future_value_get_mongoc_iovec_ptr (future_get_param (future, 1)), future_value_get_size_t (future_get_param (future, 2)), future_value_get_uint32_t (future_get_param (future, 3)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_topology_select (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_mongoc_server_description_ptr_type; future_value_set_mongoc_server_description_ptr ( &return_value, mongoc_topology_select ( future_value_get_mongoc_topology_ptr (future_get_param (future, 0)), future_value_get_mongoc_ss_optype_t (future_get_param (future, 1)), future_value_get_const_mongoc_read_prefs_ptr (future_get_param (future, 2)), future_value_get_int64_t (future_get_param (future, 3)), future_value_get_bson_error_ptr (future_get_param (future, 4)) )); future_resolve (future, return_value); return NULL; } static void * background_mongoc_client_get_gridfs (void *data) { future_t *future = (future_t *) data; future_value_t return_value; return_value.type = future_value_mongoc_gridfs_ptr_type; future_value_set_mongoc_gridfs_ptr ( &return_value, mongoc_client_get_gridfs ( future_value_get_mongoc_client_ptr (future_get_param (future, 0)), future_value_get_const_char_ptr (future_get_param (future, 1)), future_value_get_const_char_ptr (future_get_param (future, 2)), future_value_get_bson_error_ptr (future_get_param (future, 3)) )); future_resolve (future, return_value); return NULL; } future_t * future_bulk_operation_execute ( mongoc_bulk_operation_ptr bulk, bson_ptr reply, bson_error_ptr error) { future_t *future = future_new (future_value_uint32_t_type, 3); future_value_set_mongoc_bulk_operation_ptr ( future_get_param (future, 0), bulk); future_value_set_bson_ptr ( future_get_param (future, 1), reply); future_value_set_bson_error_ptr ( future_get_param (future, 2), error); future_start (future, background_mongoc_bulk_operation_execute); return future; } future_t * future_client_command_simple ( mongoc_client_ptr client, const_char_ptr db_name, const_bson_ptr command, const_mongoc_read_prefs_ptr read_prefs, bson_ptr reply, bson_error_ptr error) { future_t *future = future_new (future_value_bool_type, 6); future_value_set_mongoc_client_ptr ( future_get_param (future, 0), client); future_value_set_const_char_ptr ( future_get_param (future, 1), db_name); future_value_set_const_bson_ptr ( future_get_param (future, 2), command); future_value_set_const_mongoc_read_prefs_ptr ( future_get_param (future, 3), read_prefs); future_value_set_bson_ptr ( future_get_param (future, 4), reply); future_value_set_bson_error_ptr ( future_get_param (future, 5), error); future_start (future, background_mongoc_client_command_simple); return future; } future_t * future_client_kill_cursor ( mongoc_client_ptr client, int64_t cursor_id) { future_t *future = future_new (future_value_void_type, 2); future_value_set_mongoc_client_ptr ( future_get_param (future, 0), client); future_value_set_int64_t ( future_get_param (future, 1), cursor_id); future_start (future, background_mongoc_client_kill_cursor); return future; } future_t * future_collection_aggregate ( mongoc_collection_ptr collection, mongoc_query_flags_t flags, const_bson_ptr pipeline, const_bson_ptr options, const_mongoc_read_prefs_ptr read_prefs) { future_t *future = future_new (future_value_mongoc_cursor_ptr_type, 5); future_value_set_mongoc_collection_ptr ( future_get_param (future, 0), collection); future_value_set_mongoc_query_flags_t ( future_get_param (future, 1), flags); future_value_set_const_bson_ptr ( future_get_param (future, 2), pipeline); future_value_set_const_bson_ptr ( future_get_param (future, 3), options); future_value_set_const_mongoc_read_prefs_ptr ( future_get_param (future, 4), read_prefs); future_start (future, background_mongoc_collection_aggregate); return future; } future_t * future_collection_count ( mongoc_collection_ptr collection, mongoc_query_flags_t flags, const_bson_ptr query, int64_t skip, int64_t limit, const_mongoc_read_prefs_ptr read_prefs, bson_error_ptr error) { future_t *future = future_new (future_value_int64_t_type, 7); future_value_set_mongoc_collection_ptr ( future_get_param (future, 0), collection); future_value_set_mongoc_query_flags_t ( future_get_param (future, 1), flags); future_value_set_const_bson_ptr ( future_get_param (future, 2), query); future_value_set_int64_t ( future_get_param (future, 3), skip); future_value_set_int64_t ( future_get_param (future, 4), limit); future_value_set_const_mongoc_read_prefs_ptr ( future_get_param (future, 5), read_prefs); future_value_set_bson_error_ptr ( future_get_param (future, 6), error); future_start (future, background_mongoc_collection_count); return future; } future_t * future_collection_find_and_modify_with_opts ( mongoc_collection_ptr collection, const_bson_ptr query, const_mongoc_find_and_modify_opts_ptr opts, bson_ptr reply, bson_error_ptr error) { future_t *future = future_new (future_value_bool_type, 5); future_value_set_mongoc_collection_ptr ( future_get_param (future, 0), collection); future_value_set_const_bson_ptr ( future_get_param (future, 1), query); future_value_set_const_mongoc_find_and_modify_opts_ptr ( future_get_param (future, 2), opts); future_value_set_bson_ptr ( future_get_param (future, 3), reply); future_value_set_bson_error_ptr ( future_get_param (future, 4), error); future_start (future, background_mongoc_collection_find_and_modify_with_opts); return future; } future_t * future_collection_find_and_modify ( mongoc_collection_ptr collection, const_bson_ptr query, const_bson_ptr sort, const_bson_ptr update, const_bson_ptr fields, bool _remove, bool upsert, bool _new, bson_ptr reply, bson_error_ptr error) { future_t *future = future_new (future_value_bool_type, 10); future_value_set_mongoc_collection_ptr ( future_get_param (future, 0), collection); future_value_set_const_bson_ptr ( future_get_param (future, 1), query); future_value_set_const_bson_ptr ( future_get_param (future, 2), sort); future_value_set_const_bson_ptr ( future_get_param (future, 3), update); future_value_set_const_bson_ptr ( future_get_param (future, 4), fields); future_value_set_bool ( future_get_param (future, 5), _remove); future_value_set_bool ( future_get_param (future, 6), upsert); future_value_set_bool ( future_get_param (future, 7), _new); future_value_set_bson_ptr ( future_get_param (future, 8), reply); future_value_set_bson_error_ptr ( future_get_param (future, 9), error); future_start (future, background_mongoc_collection_find_and_modify); return future; } future_t * future_collection_insert ( mongoc_collection_ptr collection, mongoc_insert_flags_t flags, const_bson_ptr document, const_mongoc_write_concern_ptr write_concern, bson_error_ptr error) { future_t *future = future_new (future_value_bool_type, 5); future_value_set_mongoc_collection_ptr ( future_get_param (future, 0), collection); future_value_set_mongoc_insert_flags_t ( future_get_param (future, 1), flags); future_value_set_const_bson_ptr ( future_get_param (future, 2), document); future_value_set_const_mongoc_write_concern_ptr ( future_get_param (future, 3), write_concern); future_value_set_bson_error_ptr ( future_get_param (future, 4), error); future_start (future, background_mongoc_collection_insert); return future; } future_t * future_collection_insert_bulk ( mongoc_collection_ptr collection, mongoc_insert_flags_t flags, const_bson_ptr_ptr documents, uint32_t n_documents, const_mongoc_write_concern_ptr write_concern, bson_error_ptr error) { future_t *future = future_new (future_value_bool_type, 6); future_value_set_mongoc_collection_ptr ( future_get_param (future, 0), collection); future_value_set_mongoc_insert_flags_t ( future_get_param (future, 1), flags); future_value_set_const_bson_ptr_ptr ( future_get_param (future, 2), documents); future_value_set_uint32_t ( future_get_param (future, 3), n_documents); future_value_set_const_mongoc_write_concern_ptr ( future_get_param (future, 4), write_concern); future_value_set_bson_error_ptr ( future_get_param (future, 5), error); future_start (future, background_mongoc_collection_insert_bulk); return future; } future_t * future_cursor_destroy ( mongoc_cursor_ptr cursor) { future_t *future = future_new (future_value_void_type, 1); future_value_set_mongoc_cursor_ptr ( future_get_param (future, 0), cursor); future_start (future, background_mongoc_cursor_destroy); return future; } future_t * future_cursor_next ( mongoc_cursor_ptr cursor, const_bson_ptr_ptr doc) { future_t *future = future_new (future_value_bool_type, 2); future_value_set_mongoc_cursor_ptr ( future_get_param (future, 0), cursor); future_value_set_const_bson_ptr_ptr ( future_get_param (future, 1), doc); future_start (future, background_mongoc_cursor_next); return future; } future_t * future_client_get_database_names ( mongoc_client_ptr client, bson_error_ptr error) { future_t *future = future_new (future_value_char_ptr_ptr_type, 2); future_value_set_mongoc_client_ptr ( future_get_param (future, 0), client); future_value_set_bson_error_ptr ( future_get_param (future, 1), error); future_start (future, background_mongoc_client_get_database_names); return future; } future_t * future_database_get_collection_names ( mongoc_database_ptr database, bson_error_ptr error) { future_t *future = future_new (future_value_char_ptr_ptr_type, 2); future_value_set_mongoc_database_ptr ( future_get_param (future, 0), database); future_value_set_bson_error_ptr ( future_get_param (future, 1), error); future_start (future, background_mongoc_database_get_collection_names); return future; } future_t * future_gridfs_file_readv ( mongoc_gridfs_file_ptr file, mongoc_iovec_ptr iov, size_t iovcnt, size_t min_bytes, uint32_t timeout_msec) { future_t *future = future_new (future_value_ssize_t_type, 5); future_value_set_mongoc_gridfs_file_ptr ( future_get_param (future, 0), file); future_value_set_mongoc_iovec_ptr ( future_get_param (future, 1), iov); future_value_set_size_t ( future_get_param (future, 2), iovcnt); future_value_set_size_t ( future_get_param (future, 3), min_bytes); future_value_set_uint32_t ( future_get_param (future, 4), timeout_msec); future_start (future, background_mongoc_gridfs_file_readv); return future; } future_t * future_gridfs_file_seek ( mongoc_gridfs_file_ptr file, int64_t delta, int whence) { future_t *future = future_new (future_value_int_type, 3); future_value_set_mongoc_gridfs_file_ptr ( future_get_param (future, 0), file); future_value_set_int64_t ( future_get_param (future, 1), delta); future_value_set_int ( future_get_param (future, 2), whence); future_start (future, background_mongoc_gridfs_file_seek); return future; } future_t * future_gridfs_file_writev ( mongoc_gridfs_file_ptr file, mongoc_iovec_ptr iov, size_t iovcnt, uint32_t timeout_msec) { future_t *future = future_new (future_value_ssize_t_type, 4); future_value_set_mongoc_gridfs_file_ptr ( future_get_param (future, 0), file); future_value_set_mongoc_iovec_ptr ( future_get_param (future, 1), iov); future_value_set_size_t ( future_get_param (future, 2), iovcnt); future_value_set_uint32_t ( future_get_param (future, 3), timeout_msec); future_start (future, background_mongoc_gridfs_file_writev); return future; } future_t * future_topology_select ( mongoc_topology_ptr topology, mongoc_ss_optype_t optype, const_mongoc_read_prefs_ptr read_prefs, int64_t local_threshold_ms, bson_error_ptr error) { future_t *future = future_new (future_value_mongoc_server_description_ptr_type, 5); future_value_set_mongoc_topology_ptr ( future_get_param (future, 0), topology); future_value_set_mongoc_ss_optype_t ( future_get_param (future, 1), optype); future_value_set_const_mongoc_read_prefs_ptr ( future_get_param (future, 2), read_prefs); future_value_set_int64_t ( future_get_param (future, 3), local_threshold_ms); future_value_set_bson_error_ptr ( future_get_param (future, 4), error); future_start (future, background_mongoc_topology_select); return future; } future_t * future_client_get_gridfs ( mongoc_client_ptr client, const_char_ptr db, const_char_ptr prefix, bson_error_ptr error) { future_t *future = future_new (future_value_mongoc_gridfs_ptr_type, 4); future_value_set_mongoc_client_ptr ( future_get_param (future, 0), client); future_value_set_const_char_ptr ( future_get_param (future, 1), db); future_value_set_const_char_ptr ( future_get_param (future, 2), prefix); future_value_set_bson_error_ptr ( future_get_param (future, 3), error); future_start (future, background_mongoc_client_get_gridfs); return future; } libmongoc-1.3.1/tests/mock_server/future-functions.h000066400000000000000000000064331264720626300226550ustar00rootroot00000000000000#ifndef FUTURE_FUNCTIONS_H #define FUTURE_FUNCTIONS_H #include "future-value.h" #include "future.h" #include "mongoc-bulk-operation.h" /************************************************** * * Generated by build/generate-future-functions.py. * * DO NOT EDIT THIS FILE. * *************************************************/ future_t * future_bulk_operation_execute ( mongoc_bulk_operation_ptr bulk, bson_ptr reply, bson_error_ptr error ); future_t * future_client_command_simple ( mongoc_client_ptr client, const_char_ptr db_name, const_bson_ptr command, const_mongoc_read_prefs_ptr read_prefs, bson_ptr reply, bson_error_ptr error ); future_t * future_client_kill_cursor ( mongoc_client_ptr client, int64_t cursor_id ); future_t * future_collection_aggregate ( mongoc_collection_ptr collection, mongoc_query_flags_t flags, const_bson_ptr pipeline, const_bson_ptr options, const_mongoc_read_prefs_ptr read_prefs ); future_t * future_collection_count ( mongoc_collection_ptr collection, mongoc_query_flags_t flags, const_bson_ptr query, int64_t skip, int64_t limit, const_mongoc_read_prefs_ptr read_prefs, bson_error_ptr error ); future_t * future_collection_find_and_modify_with_opts ( mongoc_collection_ptr collection, const_bson_ptr query, const_mongoc_find_and_modify_opts_ptr opts, bson_ptr reply, bson_error_ptr error ); future_t * future_collection_find_and_modify ( mongoc_collection_ptr collection, const_bson_ptr query, const_bson_ptr sort, const_bson_ptr update, const_bson_ptr fields, bool _remove, bool upsert, bool _new, bson_ptr reply, bson_error_ptr error ); future_t * future_collection_insert ( mongoc_collection_ptr collection, mongoc_insert_flags_t flags, const_bson_ptr document, const_mongoc_write_concern_ptr write_concern, bson_error_ptr error ); future_t * future_collection_insert_bulk ( mongoc_collection_ptr collection, mongoc_insert_flags_t flags, const_bson_ptr_ptr documents, uint32_t n_documents, const_mongoc_write_concern_ptr write_concern, bson_error_ptr error ); future_t * future_cursor_destroy ( mongoc_cursor_ptr cursor ); future_t * future_cursor_next ( mongoc_cursor_ptr cursor, const_bson_ptr_ptr doc ); future_t * future_client_get_database_names ( mongoc_client_ptr client, bson_error_ptr error ); future_t * future_database_get_collection_names ( mongoc_database_ptr database, bson_error_ptr error ); future_t * future_gridfs_file_readv ( mongoc_gridfs_file_ptr file, mongoc_iovec_ptr iov, size_t iovcnt, size_t min_bytes, uint32_t timeout_msec ); future_t * future_gridfs_file_seek ( mongoc_gridfs_file_ptr file, int64_t delta, int whence ); future_t * future_gridfs_file_writev ( mongoc_gridfs_file_ptr file, mongoc_iovec_ptr iov, size_t iovcnt, uint32_t timeout_msec ); future_t * future_topology_select ( mongoc_topology_ptr topology, mongoc_ss_optype_t optype, const_mongoc_read_prefs_ptr read_prefs, int64_t local_threshold_ms, bson_error_ptr error ); future_t * future_client_get_gridfs ( mongoc_client_ptr client, const_char_ptr db, const_char_ptr prefix, bson_error_ptr error ); #endif /* FUTURE_FUNCTIONS_H */libmongoc-1.3.1/tests/mock_server/future-value.c000066400000000000000000000303341264720626300217510ustar00rootroot00000000000000#include "future-value.h" /************************************************** * * Generated by build/generate-future-functions.py. * * DO NOT EDIT THIS FILE. * *************************************************/ future_value_t * future_value_new () { return (future_value_t *) bson_malloc0 (sizeof (future_value_t)); } void future_value_set_void (future_value_t *future_value) { future_value->type = future_value_void_type; } void future_value_get_void (future_value_t *future_value) { assert (future_value->type == future_value_void_type); } void future_value_set_bool(future_value_t *future_value, bool value) { future_value->type = future_value_bool_type; future_value->bool_value = value; } bool future_value_get_bool (future_value_t *future_value) { assert (future_value->type == future_value_bool_type); return future_value->bool_value; } void future_value_set_char_ptr(future_value_t *future_value, char_ptr value) { future_value->type = future_value_char_ptr_type; future_value->char_ptr_value = value; } char_ptr future_value_get_char_ptr (future_value_t *future_value) { assert (future_value->type == future_value_char_ptr_type); return future_value->char_ptr_value; } void future_value_set_char_ptr_ptr(future_value_t *future_value, char_ptr_ptr value) { future_value->type = future_value_char_ptr_ptr_type; future_value->char_ptr_ptr_value = value; } char_ptr_ptr future_value_get_char_ptr_ptr (future_value_t *future_value) { assert (future_value->type == future_value_char_ptr_ptr_type); return future_value->char_ptr_ptr_value; } void future_value_set_int(future_value_t *future_value, int value) { future_value->type = future_value_int_type; future_value->int_value = value; } int future_value_get_int (future_value_t *future_value) { assert (future_value->type == future_value_int_type); return future_value->int_value; } void future_value_set_int64_t(future_value_t *future_value, int64_t value) { future_value->type = future_value_int64_t_type; future_value->int64_t_value = value; } int64_t future_value_get_int64_t (future_value_t *future_value) { assert (future_value->type == future_value_int64_t_type); return future_value->int64_t_value; } void future_value_set_size_t(future_value_t *future_value, size_t value) { future_value->type = future_value_size_t_type; future_value->size_t_value = value; } size_t future_value_get_size_t (future_value_t *future_value) { assert (future_value->type == future_value_size_t_type); return future_value->size_t_value; } void future_value_set_ssize_t(future_value_t *future_value, ssize_t value) { future_value->type = future_value_ssize_t_type; future_value->ssize_t_value = value; } ssize_t future_value_get_ssize_t (future_value_t *future_value) { assert (future_value->type == future_value_ssize_t_type); return future_value->ssize_t_value; } void future_value_set_uint32_t(future_value_t *future_value, uint32_t value) { future_value->type = future_value_uint32_t_type; future_value->uint32_t_value = value; } uint32_t future_value_get_uint32_t (future_value_t *future_value) { assert (future_value->type == future_value_uint32_t_type); return future_value->uint32_t_value; } void future_value_set_const_char_ptr(future_value_t *future_value, const_char_ptr value) { future_value->type = future_value_const_char_ptr_type; future_value->const_char_ptr_value = value; } const_char_ptr future_value_get_const_char_ptr (future_value_t *future_value) { assert (future_value->type == future_value_const_char_ptr_type); return future_value->const_char_ptr_value; } void future_value_set_bson_error_ptr(future_value_t *future_value, bson_error_ptr value) { future_value->type = future_value_bson_error_ptr_type; future_value->bson_error_ptr_value = value; } bson_error_ptr future_value_get_bson_error_ptr (future_value_t *future_value) { assert (future_value->type == future_value_bson_error_ptr_type); return future_value->bson_error_ptr_value; } void future_value_set_bson_ptr(future_value_t *future_value, bson_ptr value) { future_value->type = future_value_bson_ptr_type; future_value->bson_ptr_value = value; } bson_ptr future_value_get_bson_ptr (future_value_t *future_value) { assert (future_value->type == future_value_bson_ptr_type); return future_value->bson_ptr_value; } void future_value_set_const_bson_ptr(future_value_t *future_value, const_bson_ptr value) { future_value->type = future_value_const_bson_ptr_type; future_value->const_bson_ptr_value = value; } const_bson_ptr future_value_get_const_bson_ptr (future_value_t *future_value) { assert (future_value->type == future_value_const_bson_ptr_type); return future_value->const_bson_ptr_value; } void future_value_set_const_bson_ptr_ptr(future_value_t *future_value, const_bson_ptr_ptr value) { future_value->type = future_value_const_bson_ptr_ptr_type; future_value->const_bson_ptr_ptr_value = value; } const_bson_ptr_ptr future_value_get_const_bson_ptr_ptr (future_value_t *future_value) { assert (future_value->type == future_value_const_bson_ptr_ptr_type); return future_value->const_bson_ptr_ptr_value; } void future_value_set_mongoc_bulk_operation_ptr(future_value_t *future_value, mongoc_bulk_operation_ptr value) { future_value->type = future_value_mongoc_bulk_operation_ptr_type; future_value->mongoc_bulk_operation_ptr_value = value; } mongoc_bulk_operation_ptr future_value_get_mongoc_bulk_operation_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_bulk_operation_ptr_type); return future_value->mongoc_bulk_operation_ptr_value; } void future_value_set_mongoc_client_ptr(future_value_t *future_value, mongoc_client_ptr value) { future_value->type = future_value_mongoc_client_ptr_type; future_value->mongoc_client_ptr_value = value; } mongoc_client_ptr future_value_get_mongoc_client_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_client_ptr_type); return future_value->mongoc_client_ptr_value; } void future_value_set_mongoc_collection_ptr(future_value_t *future_value, mongoc_collection_ptr value) { future_value->type = future_value_mongoc_collection_ptr_type; future_value->mongoc_collection_ptr_value = value; } mongoc_collection_ptr future_value_get_mongoc_collection_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_collection_ptr_type); return future_value->mongoc_collection_ptr_value; } void future_value_set_mongoc_cursor_ptr(future_value_t *future_value, mongoc_cursor_ptr value) { future_value->type = future_value_mongoc_cursor_ptr_type; future_value->mongoc_cursor_ptr_value = value; } mongoc_cursor_ptr future_value_get_mongoc_cursor_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_cursor_ptr_type); return future_value->mongoc_cursor_ptr_value; } void future_value_set_mongoc_database_ptr(future_value_t *future_value, mongoc_database_ptr value) { future_value->type = future_value_mongoc_database_ptr_type; future_value->mongoc_database_ptr_value = value; } mongoc_database_ptr future_value_get_mongoc_database_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_database_ptr_type); return future_value->mongoc_database_ptr_value; } void future_value_set_mongoc_gridfs_file_ptr(future_value_t *future_value, mongoc_gridfs_file_ptr value) { future_value->type = future_value_mongoc_gridfs_file_ptr_type; future_value->mongoc_gridfs_file_ptr_value = value; } mongoc_gridfs_file_ptr future_value_get_mongoc_gridfs_file_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_gridfs_file_ptr_type); return future_value->mongoc_gridfs_file_ptr_value; } void future_value_set_mongoc_gridfs_ptr(future_value_t *future_value, mongoc_gridfs_ptr value) { future_value->type = future_value_mongoc_gridfs_ptr_type; future_value->mongoc_gridfs_ptr_value = value; } mongoc_gridfs_ptr future_value_get_mongoc_gridfs_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_gridfs_ptr_type); return future_value->mongoc_gridfs_ptr_value; } void future_value_set_mongoc_insert_flags_t(future_value_t *future_value, mongoc_insert_flags_t value) { future_value->type = future_value_mongoc_insert_flags_t_type; future_value->mongoc_insert_flags_t_value = value; } mongoc_insert_flags_t future_value_get_mongoc_insert_flags_t (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_insert_flags_t_type); return future_value->mongoc_insert_flags_t_value; } void future_value_set_mongoc_iovec_ptr(future_value_t *future_value, mongoc_iovec_ptr value) { future_value->type = future_value_mongoc_iovec_ptr_type; future_value->mongoc_iovec_ptr_value = value; } mongoc_iovec_ptr future_value_get_mongoc_iovec_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_iovec_ptr_type); return future_value->mongoc_iovec_ptr_value; } void future_value_set_mongoc_query_flags_t(future_value_t *future_value, mongoc_query_flags_t value) { future_value->type = future_value_mongoc_query_flags_t_type; future_value->mongoc_query_flags_t_value = value; } mongoc_query_flags_t future_value_get_mongoc_query_flags_t (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_query_flags_t_type); return future_value->mongoc_query_flags_t_value; } void future_value_set_mongoc_server_description_ptr(future_value_t *future_value, mongoc_server_description_ptr value) { future_value->type = future_value_mongoc_server_description_ptr_type; future_value->mongoc_server_description_ptr_value = value; } mongoc_server_description_ptr future_value_get_mongoc_server_description_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_server_description_ptr_type); return future_value->mongoc_server_description_ptr_value; } void future_value_set_mongoc_ss_optype_t(future_value_t *future_value, mongoc_ss_optype_t value) { future_value->type = future_value_mongoc_ss_optype_t_type; future_value->mongoc_ss_optype_t_value = value; } mongoc_ss_optype_t future_value_get_mongoc_ss_optype_t (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_ss_optype_t_type); return future_value->mongoc_ss_optype_t_value; } void future_value_set_mongoc_topology_ptr(future_value_t *future_value, mongoc_topology_ptr value) { future_value->type = future_value_mongoc_topology_ptr_type; future_value->mongoc_topology_ptr_value = value; } mongoc_topology_ptr future_value_get_mongoc_topology_ptr (future_value_t *future_value) { assert (future_value->type == future_value_mongoc_topology_ptr_type); return future_value->mongoc_topology_ptr_value; } void future_value_set_const_mongoc_find_and_modify_opts_ptr(future_value_t *future_value, const_mongoc_find_and_modify_opts_ptr value) { future_value->type = future_value_const_mongoc_find_and_modify_opts_ptr_type; future_value->const_mongoc_find_and_modify_opts_ptr_value = value; } const_mongoc_find_and_modify_opts_ptr future_value_get_const_mongoc_find_and_modify_opts_ptr (future_value_t *future_value) { assert (future_value->type == future_value_const_mongoc_find_and_modify_opts_ptr_type); return future_value->const_mongoc_find_and_modify_opts_ptr_value; } void future_value_set_const_mongoc_read_prefs_ptr(future_value_t *future_value, const_mongoc_read_prefs_ptr value) { future_value->type = future_value_const_mongoc_read_prefs_ptr_type; future_value->const_mongoc_read_prefs_ptr_value = value; } const_mongoc_read_prefs_ptr future_value_get_const_mongoc_read_prefs_ptr (future_value_t *future_value) { assert (future_value->type == future_value_const_mongoc_read_prefs_ptr_type); return future_value->const_mongoc_read_prefs_ptr_value; } void future_value_set_const_mongoc_write_concern_ptr(future_value_t *future_value, const_mongoc_write_concern_ptr value) { future_value->type = future_value_const_mongoc_write_concern_ptr_type; future_value->const_mongoc_write_concern_ptr_value = value; } const_mongoc_write_concern_ptr future_value_get_const_mongoc_write_concern_ptr (future_value_t *future_value) { assert (future_value->type == future_value_const_mongoc_write_concern_ptr_type); return future_value->const_mongoc_write_concern_ptr_value; } libmongoc-1.3.1/tests/mock_server/future-value.h000066400000000000000000000233761264720626300217660ustar00rootroot00000000000000#ifndef FUTURE_VALUE_H #define FUTURE_VALUE_H #include #include #include "mongoc-server-description.h" #include "mongoc-topology-private.h" /************************************************** * * Generated by build/generate-future-functions.py. * * DO NOT EDIT THIS FILE. * *************************************************/ typedef char * char_ptr; typedef char ** char_ptr_ptr; typedef const char * const_char_ptr; typedef bson_error_t * bson_error_ptr; typedef bson_t * bson_ptr; typedef const bson_t * const_bson_ptr; typedef const bson_t ** const_bson_ptr_ptr; typedef mongoc_bulk_operation_t * mongoc_bulk_operation_ptr; typedef mongoc_client_t * mongoc_client_ptr; typedef mongoc_collection_t * mongoc_collection_ptr; typedef mongoc_cursor_t * mongoc_cursor_ptr; typedef mongoc_database_t * mongoc_database_ptr; typedef mongoc_gridfs_file_t * mongoc_gridfs_file_ptr; typedef mongoc_gridfs_t * mongoc_gridfs_ptr; typedef mongoc_iovec_t * mongoc_iovec_ptr; typedef mongoc_server_description_t * mongoc_server_description_ptr; typedef mongoc_topology_t * mongoc_topology_ptr; typedef const mongoc_find_and_modify_opts_t * const_mongoc_find_and_modify_opts_ptr; typedef const mongoc_read_prefs_t * const_mongoc_read_prefs_ptr; typedef const mongoc_write_concern_t * const_mongoc_write_concern_ptr; typedef enum { future_value_no_type = 0, future_value_bool_type, future_value_char_ptr_type, future_value_char_ptr_ptr_type, future_value_int_type, future_value_int64_t_type, future_value_size_t_type, future_value_ssize_t_type, future_value_uint32_t_type, future_value_const_char_ptr_type, future_value_bson_error_ptr_type, future_value_bson_ptr_type, future_value_const_bson_ptr_type, future_value_const_bson_ptr_ptr_type, future_value_mongoc_bulk_operation_ptr_type, future_value_mongoc_client_ptr_type, future_value_mongoc_collection_ptr_type, future_value_mongoc_cursor_ptr_type, future_value_mongoc_database_ptr_type, future_value_mongoc_gridfs_file_ptr_type, future_value_mongoc_gridfs_ptr_type, future_value_mongoc_insert_flags_t_type, future_value_mongoc_iovec_ptr_type, future_value_mongoc_query_flags_t_type, future_value_mongoc_server_description_ptr_type, future_value_mongoc_ss_optype_t_type, future_value_mongoc_topology_ptr_type, future_value_const_mongoc_find_and_modify_opts_ptr_type, future_value_const_mongoc_read_prefs_ptr_type, future_value_const_mongoc_write_concern_ptr_type, future_value_void_type, } future_value_type_t; typedef struct _future_value_t { future_value_type_t type; union { bool bool_value; char_ptr char_ptr_value; char_ptr_ptr char_ptr_ptr_value; int int_value; int64_t int64_t_value; size_t size_t_value; ssize_t ssize_t_value; uint32_t uint32_t_value; const_char_ptr const_char_ptr_value; bson_error_ptr bson_error_ptr_value; bson_ptr bson_ptr_value; const_bson_ptr const_bson_ptr_value; const_bson_ptr_ptr const_bson_ptr_ptr_value; mongoc_bulk_operation_ptr mongoc_bulk_operation_ptr_value; mongoc_client_ptr mongoc_client_ptr_value; mongoc_collection_ptr mongoc_collection_ptr_value; mongoc_cursor_ptr mongoc_cursor_ptr_value; mongoc_database_ptr mongoc_database_ptr_value; mongoc_gridfs_file_ptr mongoc_gridfs_file_ptr_value; mongoc_gridfs_ptr mongoc_gridfs_ptr_value; mongoc_insert_flags_t mongoc_insert_flags_t_value; mongoc_iovec_ptr mongoc_iovec_ptr_value; mongoc_query_flags_t mongoc_query_flags_t_value; mongoc_server_description_ptr mongoc_server_description_ptr_value; mongoc_ss_optype_t mongoc_ss_optype_t_value; mongoc_topology_ptr mongoc_topology_ptr_value; const_mongoc_find_and_modify_opts_ptr const_mongoc_find_and_modify_opts_ptr_value; const_mongoc_read_prefs_ptr const_mongoc_read_prefs_ptr_value; const_mongoc_write_concern_ptr const_mongoc_write_concern_ptr_value; }; } future_value_t; future_value_t *future_value_new (); #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" #endif void future_value_set_void (future_value_t *future_value); void future_value_get_void (future_value_t *future_value); void future_value_set_bool( future_value_t *future_value, bool value); bool future_value_get_bool ( future_value_t *future_value); void future_value_set_char_ptr( future_value_t *future_value, char_ptr value); char_ptr future_value_get_char_ptr ( future_value_t *future_value); void future_value_set_char_ptr_ptr( future_value_t *future_value, char_ptr_ptr value); char_ptr_ptr future_value_get_char_ptr_ptr ( future_value_t *future_value); void future_value_set_int( future_value_t *future_value, int value); int future_value_get_int ( future_value_t *future_value); void future_value_set_int64_t( future_value_t *future_value, int64_t value); int64_t future_value_get_int64_t ( future_value_t *future_value); void future_value_set_size_t( future_value_t *future_value, size_t value); size_t future_value_get_size_t ( future_value_t *future_value); void future_value_set_ssize_t( future_value_t *future_value, ssize_t value); ssize_t future_value_get_ssize_t ( future_value_t *future_value); void future_value_set_uint32_t( future_value_t *future_value, uint32_t value); uint32_t future_value_get_uint32_t ( future_value_t *future_value); void future_value_set_const_char_ptr( future_value_t *future_value, const_char_ptr value); const_char_ptr future_value_get_const_char_ptr ( future_value_t *future_value); void future_value_set_bson_error_ptr( future_value_t *future_value, bson_error_ptr value); bson_error_ptr future_value_get_bson_error_ptr ( future_value_t *future_value); void future_value_set_bson_ptr( future_value_t *future_value, bson_ptr value); bson_ptr future_value_get_bson_ptr ( future_value_t *future_value); void future_value_set_const_bson_ptr( future_value_t *future_value, const_bson_ptr value); const_bson_ptr future_value_get_const_bson_ptr ( future_value_t *future_value); void future_value_set_const_bson_ptr_ptr( future_value_t *future_value, const_bson_ptr_ptr value); const_bson_ptr_ptr future_value_get_const_bson_ptr_ptr ( future_value_t *future_value); void future_value_set_mongoc_bulk_operation_ptr( future_value_t *future_value, mongoc_bulk_operation_ptr value); mongoc_bulk_operation_ptr future_value_get_mongoc_bulk_operation_ptr ( future_value_t *future_value); void future_value_set_mongoc_client_ptr( future_value_t *future_value, mongoc_client_ptr value); mongoc_client_ptr future_value_get_mongoc_client_ptr ( future_value_t *future_value); void future_value_set_mongoc_collection_ptr( future_value_t *future_value, mongoc_collection_ptr value); mongoc_collection_ptr future_value_get_mongoc_collection_ptr ( future_value_t *future_value); void future_value_set_mongoc_cursor_ptr( future_value_t *future_value, mongoc_cursor_ptr value); mongoc_cursor_ptr future_value_get_mongoc_cursor_ptr ( future_value_t *future_value); void future_value_set_mongoc_database_ptr( future_value_t *future_value, mongoc_database_ptr value); mongoc_database_ptr future_value_get_mongoc_database_ptr ( future_value_t *future_value); void future_value_set_mongoc_gridfs_file_ptr( future_value_t *future_value, mongoc_gridfs_file_ptr value); mongoc_gridfs_file_ptr future_value_get_mongoc_gridfs_file_ptr ( future_value_t *future_value); void future_value_set_mongoc_gridfs_ptr( future_value_t *future_value, mongoc_gridfs_ptr value); mongoc_gridfs_ptr future_value_get_mongoc_gridfs_ptr ( future_value_t *future_value); void future_value_set_mongoc_insert_flags_t( future_value_t *future_value, mongoc_insert_flags_t value); mongoc_insert_flags_t future_value_get_mongoc_insert_flags_t ( future_value_t *future_value); void future_value_set_mongoc_iovec_ptr( future_value_t *future_value, mongoc_iovec_ptr value); mongoc_iovec_ptr future_value_get_mongoc_iovec_ptr ( future_value_t *future_value); void future_value_set_mongoc_query_flags_t( future_value_t *future_value, mongoc_query_flags_t value); mongoc_query_flags_t future_value_get_mongoc_query_flags_t ( future_value_t *future_value); void future_value_set_mongoc_server_description_ptr( future_value_t *future_value, mongoc_server_description_ptr value); mongoc_server_description_ptr future_value_get_mongoc_server_description_ptr ( future_value_t *future_value); void future_value_set_mongoc_ss_optype_t( future_value_t *future_value, mongoc_ss_optype_t value); mongoc_ss_optype_t future_value_get_mongoc_ss_optype_t ( future_value_t *future_value); void future_value_set_mongoc_topology_ptr( future_value_t *future_value, mongoc_topology_ptr value); mongoc_topology_ptr future_value_get_mongoc_topology_ptr ( future_value_t *future_value); void future_value_set_const_mongoc_find_and_modify_opts_ptr( future_value_t *future_value, const_mongoc_find_and_modify_opts_ptr value); const_mongoc_find_and_modify_opts_ptr future_value_get_const_mongoc_find_and_modify_opts_ptr ( future_value_t *future_value); void future_value_set_const_mongoc_read_prefs_ptr( future_value_t *future_value, const_mongoc_read_prefs_ptr value); const_mongoc_read_prefs_ptr future_value_get_const_mongoc_read_prefs_ptr ( future_value_t *future_value); void future_value_set_const_mongoc_write_concern_ptr( future_value_t *future_value, const_mongoc_write_concern_ptr value); const_mongoc_write_concern_ptr future_value_get_const_mongoc_write_concern_ptr ( future_value_t *future_value); #ifdef __clang__ #pragma clang diagnostic pop #endif #endif /* FUTURE_VALUE_H */ libmongoc-1.3.1/tests/mock_server/future.c000066400000000000000000000227111264720626300206370ustar00rootroot00000000000000#include #include "mongoc-array-private.h" #include "mongoc-thread-private.h" #include "future.h" #include "../test-libmongoc.h" /************************************************** * * Generated by build/generate-future-functions.py. * * DO NOT EDIT THIS FILE. * *************************************************/ #define DEFAULT_FUTURE_TIMEOUT_MS 10 * 1000 static int64_t get_future_timeout_ms () { return test_framework_getenv_int64 ("MONGOC_TEST_FUTURE_TIMEOUT_MS", DEFAULT_FUTURE_TIMEOUT_MS); } void future_get_void (future_t *future) { if (!future_wait (future)) { fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } } bool future_get_bool (future_t *future) { if (future_wait (future)) { return future_value_get_bool (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } char_ptr future_get_char_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_char_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } char_ptr_ptr future_get_char_ptr_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_char_ptr_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } int future_get_int (future_t *future) { if (future_wait (future)) { return future_value_get_int (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } int64_t future_get_int64_t (future_t *future) { if (future_wait (future)) { return future_value_get_int64_t (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } size_t future_get_size_t (future_t *future) { if (future_wait (future)) { return future_value_get_size_t (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } ssize_t future_get_ssize_t (future_t *future) { if (future_wait (future)) { return future_value_get_ssize_t (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } uint32_t future_get_uint32_t (future_t *future) { if (future_wait (future)) { return future_value_get_uint32_t (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } const_char_ptr future_get_const_char_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_const_char_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } bson_error_ptr future_get_bson_error_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_bson_error_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } bson_ptr future_get_bson_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_bson_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } const_bson_ptr future_get_const_bson_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_const_bson_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } const_bson_ptr_ptr future_get_const_bson_ptr_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_const_bson_ptr_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_bulk_operation_ptr future_get_mongoc_bulk_operation_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_bulk_operation_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_client_ptr future_get_mongoc_client_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_client_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_collection_ptr future_get_mongoc_collection_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_collection_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_cursor_ptr future_get_mongoc_cursor_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_cursor_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_database_ptr future_get_mongoc_database_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_database_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_gridfs_file_ptr future_get_mongoc_gridfs_file_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_gridfs_file_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_gridfs_ptr future_get_mongoc_gridfs_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_gridfs_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_insert_flags_t future_get_mongoc_insert_flags_t (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_insert_flags_t (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_iovec_ptr future_get_mongoc_iovec_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_iovec_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_query_flags_t future_get_mongoc_query_flags_t (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_query_flags_t (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_server_description_ptr future_get_mongoc_server_description_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_server_description_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_ss_optype_t future_get_mongoc_ss_optype_t (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_ss_optype_t (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } mongoc_topology_ptr future_get_mongoc_topology_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_mongoc_topology_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } const_mongoc_find_and_modify_opts_ptr future_get_const_mongoc_find_and_modify_opts_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_const_mongoc_find_and_modify_opts_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } const_mongoc_read_prefs_ptr future_get_const_mongoc_read_prefs_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_const_mongoc_read_prefs_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } const_mongoc_write_concern_ptr future_get_const_mongoc_write_concern_ptr (future_t *future) { if (future_wait (future)) { return future_value_get_const_mongoc_write_concern_ptr (&future->return_value); } fprintf (stderr, "%s timed out\n", BSON_FUNC); abort (); } future_t * future_new (future_value_type_t return_type, int argc) { future_t *future; future = (future_t *)bson_malloc0 (sizeof *future); future->return_value.type = return_type; future->argc = argc; future->argv = (future_value_t *)bson_malloc0 ((size_t) argc * sizeof(future_value_t)); mongoc_cond_init (&future->cond); mongoc_mutex_init (&future->mutex); return future; } future_value_t * future_get_param (future_t *future, int i) { return &future->argv[i]; } void future_start (future_t *future, void *(*start_routine)(void *)) { int r = mongoc_thread_create (&future->thread, start_routine, (void *) future); assert (!r); } void future_resolve (future_t *future, future_value_t return_value) { mongoc_mutex_lock (&future->mutex); assert (!future->resolved); assert (future->return_value.type == return_value.type); future->return_value = return_value; future->resolved = true; mongoc_cond_signal (&future->cond); mongoc_mutex_unlock (&future->mutex); } bool future_wait (future_t *future) { int64_t deadline = bson_get_monotonic_time () + get_future_timeout_ms (); bool resolved; mongoc_mutex_lock (&future->mutex); while (!future->resolved && bson_get_monotonic_time () <= deadline) { mongoc_cond_timedwait (&future->cond, &future->mutex, get_future_timeout_ms ()); } resolved = future->resolved; mongoc_mutex_unlock (&future->mutex); if (resolved) { future->awaited = true; /* free memory */ mongoc_thread_join (future->thread); } return resolved; } void future_destroy (future_t *future) { assert (future->awaited); bson_free (future->argv); mongoc_cond_destroy (&future->cond); mongoc_mutex_destroy (&future->mutex); bson_free (future); } libmongoc-1.3.1/tests/mock_server/future.h000066400000000000000000000055721264720626300206520ustar00rootroot00000000000000#ifndef FUTURE_H #define FUTURE_H #include #include "future-value.h" #include "mongoc-thread-private.h" /************************************************** * * Generated by build/generate-future-functions.py. * * DO NOT EDIT THIS FILE. * *************************************************/ typedef struct { bool resolved; bool awaited; future_value_t return_value; int argc; future_value_t *argv; mongoc_cond_t cond; mongoc_mutex_t mutex; mongoc_thread_t thread; } future_t; future_t *future_new (future_value_type_t return_type, int argc); future_value_t *future_get_param (future_t *future, int i); void future_start (future_t *future, void *(*start_routine)(void *)); void future_resolve (future_t *future, future_value_t return_value); bool future_wait (future_t *future); void future_get_void (future_t *future); bool future_get_bool (future_t *future); char_ptr future_get_char_ptr (future_t *future); char_ptr_ptr future_get_char_ptr_ptr (future_t *future); int future_get_int (future_t *future); int64_t future_get_int64_t (future_t *future); size_t future_get_size_t (future_t *future); ssize_t future_get_ssize_t (future_t *future); uint32_t future_get_uint32_t (future_t *future); const_char_ptr future_get_const_char_ptr (future_t *future); bson_error_ptr future_get_bson_error_ptr (future_t *future); bson_ptr future_get_bson_ptr (future_t *future); const_bson_ptr future_get_const_bson_ptr (future_t *future); const_bson_ptr_ptr future_get_const_bson_ptr_ptr (future_t *future); mongoc_bulk_operation_ptr future_get_mongoc_bulk_operation_ptr (future_t *future); mongoc_client_ptr future_get_mongoc_client_ptr (future_t *future); mongoc_collection_ptr future_get_mongoc_collection_ptr (future_t *future); mongoc_cursor_ptr future_get_mongoc_cursor_ptr (future_t *future); mongoc_database_ptr future_get_mongoc_database_ptr (future_t *future); mongoc_gridfs_file_ptr future_get_mongoc_gridfs_file_ptr (future_t *future); mongoc_gridfs_ptr future_get_mongoc_gridfs_ptr (future_t *future); mongoc_insert_flags_t future_get_mongoc_insert_flags_t (future_t *future); mongoc_iovec_ptr future_get_mongoc_iovec_ptr (future_t *future); mongoc_query_flags_t future_get_mongoc_query_flags_t (future_t *future); mongoc_server_description_ptr future_get_mongoc_server_description_ptr (future_t *future); mongoc_ss_optype_t future_get_mongoc_ss_optype_t (future_t *future); mongoc_topology_ptr future_get_mongoc_topology_ptr (future_t *future); const_mongoc_find_and_modify_opts_ptr future_get_const_mongoc_find_and_modify_opts_ptr (future_t *future); const_mongoc_read_prefs_ptr future_get_const_mongoc_read_prefs_ptr (future_t *future); const_mongoc_write_concern_ptr future_get_const_mongoc_write_concern_ptr (future_t *future); void future_destroy (future_t *future); #endif /* FUTURE_H */libmongoc-1.3.1/tests/mock_server/mock-rs.c000066400000000000000000000535731264720626300207120ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-client-private.h" #include "mock-rs.h" #include "sync-queue.h" #include "../test-libmongoc.h" struct _mock_rs_t { bool has_primary; int n_secondaries; int n_arbiters; int32_t max_wire_version; int64_t request_timeout_msec; bool verbose; mock_server_t *primary; mongoc_array_t secondaries; mongoc_array_t arbiters; mongoc_array_t servers; char *hosts_str; mongoc_uri_t *uri; sync_queue_t *q; }; mock_server_t * get_server (mongoc_array_t *servers, int i) { return _mongoc_array_index (servers, mock_server_t *, i); } void append_array (mongoc_array_t *dst, mongoc_array_t *src) { _mongoc_array_append_vals (dst, src->data, (uint32_t) src->len); } /* a string like: "localhost:1","localhost:2","localhost:3" */ char * hosts (mongoc_array_t *servers) { int i; const char *host_and_port; bson_string_t *hosts_str = bson_string_new (""); for (i = 0; i < servers->len; i++) { host_and_port = mock_server_get_host_and_port (get_server (servers, i)); bson_string_append_printf (hosts_str, "\"%s\"", host_and_port); if (i < servers->len - 1) { bson_string_append_printf (hosts_str, ", "); } } return bson_string_free (hosts_str, false); /* detach buffer */ } mongoc_uri_t * make_uri (mongoc_array_t *servers) { int i; const char *host_and_port; bson_string_t *uri_str = bson_string_new ("mongodb://"); mongoc_uri_t *uri; for (i = 0; i < servers->len; i++) { host_and_port = mock_server_get_host_and_port (get_server (servers, i)); bson_string_append_printf (uri_str, "%s", host_and_port); if (i < servers->len - 1) { bson_string_append_printf (uri_str, ","); } } bson_string_append_printf (uri_str, "/?replicaSet=rs"); uri = mongoc_uri_new (uri_str->str); bson_string_free (uri_str, true); return uri; } /*-------------------------------------------------------------------------- * * mock_rs_with_autoismaster -- * * A new mock replica set. Each member autoresponds to ismaster. * Call mock_rs_run to start it, then mock_rs_get_uri to connect. * * Returns: * A replica set you must mock_rs_destroy. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mock_rs_t * mock_rs_with_autoismaster (int32_t max_wire_version, bool has_primary, int n_secondaries, int n_arbiters) { mock_rs_t *rs = (mock_rs_t *)bson_malloc0 (sizeof (mock_rs_t)); rs->max_wire_version = max_wire_version; rs->has_primary = has_primary; rs->n_secondaries = n_secondaries; rs->n_arbiters = n_arbiters; rs->request_timeout_msec = 10 * 1000; _mongoc_array_init (&rs->secondaries, sizeof (mock_server_t *)); _mongoc_array_init (&rs->arbiters, sizeof (mock_server_t *)); _mongoc_array_init (&rs->servers, sizeof (mock_server_t *)); rs->q = q_new (); rs->verbose = test_framework_getenv_bool ("MONGOC_TEST_SERVER_VERBOSE"); return rs; } /*-------------------------------------------------------------------------- * * mock_rs_set_verbose -- * * Tell the replica set whether to log during normal operation. * *-------------------------------------------------------------------------- */ void mock_rs_set_verbose (mock_rs_t *rs, bool verbose) { int i; rs->verbose = true; for (i = 0; i < rs->servers.len; i++) { mock_server_set_verbose (get_server (&rs->servers, i), verbose); } } /*-------------------------------------------------------------------------- * * mock_rs_get_request_timeout_msec -- * * How long mock_rs_receives_* functions wait for a client * request before giving up and returning NULL. * *-------------------------------------------------------------------------- */ int64_t mock_rs_get_request_timeout_msec (mock_rs_t *rs) { return rs->request_timeout_msec; } /*-------------------------------------------------------------------------- * * mock_rs_set_request_timeout_msec -- * * How long mock_rs_receives_* functions wait for a client * request before giving up and returning NULL. * *-------------------------------------------------------------------------- */ void mock_rs_set_request_timeout_msec (mock_rs_t *rs, int64_t request_timeout_msec) { rs->request_timeout_msec = request_timeout_msec; } static bool rs_q_append (request_t *request, void *data) { mock_rs_t *rs = (mock_rs_t *)data; q_put (rs->q, (void *)request); return true; /* handled */ } /*-------------------------------------------------------------------------- * * mock_rs_run -- * * Start each member listening on an unused port. After this, call * mock_rs_get_uri to connect. * * Returns: * None. * * Side effects: * The replica set's URI is set. * *-------------------------------------------------------------------------- */ void mock_rs_run (mock_rs_t *rs) { int i; mock_server_t *server; char *hosts_str; char *ismaster_json; if (rs->has_primary) { /* start primary */ rs->primary = mock_server_new (); mock_server_run (rs->primary); } /* start secondaries */ _mongoc_array_init (&rs->secondaries, sizeof(mock_server_t *)); for (i = 0; i < rs->n_secondaries; i++) { server = mock_server_new (); mock_server_run (server); _mongoc_array_append_val (&rs->secondaries, server); } /* start arbiters */ _mongoc_array_init (&rs->arbiters, sizeof(mock_server_t *)); for (i = 0; i < rs->n_arbiters; i++) { server = mock_server_new (); mock_server_run (server); _mongoc_array_append_val (&rs->arbiters, server); } /* add all servers to replica set */ if (rs->has_primary) { _mongoc_array_append_val (&rs->servers, rs->primary); } append_array (&rs->servers, &rs->secondaries); append_array (&rs->servers, &rs->arbiters); /* enqueue unhandled requests in rs->q, they're retrieved with * mock_rs_receives_query() &co. rs_q_append is added first so it * runs last, after auto_ismaster. */ for (i = 0; i < rs->servers.len; i++) { mock_server_autoresponds (get_server (&rs->servers, i), rs_q_append, (void *) rs, NULL); } /* now we know all servers' ports and we have them in one array */ rs->hosts_str = hosts_str = hosts (&rs->servers); rs->uri = make_uri (&rs->servers); if (rs->has_primary) { /* primary's ismaster response */ ismaster_json = bson_strdup_printf ( "{'ok': 1, 'ismaster': true, 'secondary': false, 'maxWireVersion': %d, " "'setName': 'rs', 'hosts': [%s]}", rs->max_wire_version, hosts_str); mock_server_auto_ismaster (rs->primary, ismaster_json); bson_free (ismaster_json); } /* secondaries' ismaster response */ ismaster_json = bson_strdup_printf ( "{'ok': 1, 'ismaster': false, 'secondary': true, 'maxWireVersion': %d, " "'setName': 'rs', 'hosts': [%s]}", rs->max_wire_version, hosts_str); for (i = 0; i < rs->n_secondaries; i++) { mock_server_auto_ismaster (get_server (&rs->secondaries, i), ismaster_json); } bson_free (ismaster_json); /* arbiters' ismaster response */ ismaster_json = bson_strdup_printf ( "{'ok': 1, 'ismaster': true, 'arbiterOnly': true, 'maxWireVersion': %d, " "'setName': 'rs', 'hosts': [%s]}", rs->max_wire_version, hosts_str); for (i = 0; i < rs->n_arbiters; i++) { mock_server_auto_ismaster (get_server (&rs->arbiters, i), ismaster_json); } for (i = 0; i < rs->servers.len; i++) { mock_server_set_verbose (get_server (&rs->servers, i), rs->verbose); } bson_free (ismaster_json); } /*-------------------------------------------------------------------------- * * mock_rs_get_uri -- * * Call after mock_rs_run to get the connection string. * * Returns: * A const URI. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_uri_t * mock_rs_get_uri (mock_rs_t *rs) { return rs->uri; } /*-------------------------------------------------------------------------- * * mock_rs_receives_query -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request. * * Side effects: * None. * *-------------------------------------------------------------------------- */ request_t * mock_rs_receives_request (mock_rs_t *rs) { return (request_t *)q_get (rs->q, rs->request_timeout_msec); } /*-------------------------------------------------------------------------- * * mock_rs_receives_query -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not a query matching ns, flags, * skip, n_return, query_json, and fields_json. * *-------------------------------------------------------------------------- */ /* TODO: refactor with mock_server_receives_query, etc.? */ request_t * mock_rs_receives_query (mock_rs_t *rs, const char *ns, mongoc_query_flags_t flags, uint32_t skip, uint32_t n_return, const char *query_json, const char *fields_json) { request_t *request; request = mock_rs_receives_request (rs); if (request && !request_matches_query (request, ns, flags, skip, n_return, query_json, fields_json, false)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_server_reply_to_find -- * * Receive an OP_QUERY or a find command and reply to it. * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Side effects: * Logs and aborts if the current request is not a query or find command * matching "flags". * *-------------------------------------------------------------------------- */ /* void mock_rs_reply_to_find (mock_rs_t *rs, mongoc_query_flags_t flags, int64_t cursor_id, int32_t number_returned, const char *reply_json, bool is_command) { request_t *request; request = mock_rs_receives_request (rs); assert (request); mock_server_reply_to_find (request, flags, cursor_id, number_returned, reply_json, is_command); } */ /*-------------------------------------------------------------------------- * * mock_rs_receives_command -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not a command matching * database_name, command_name, and command_json. * *-------------------------------------------------------------------------- */ request_t * mock_rs_receives_command (mock_rs_t *rs, const char *database_name, mongoc_query_flags_t flags, const char *command_json, ...) { va_list args; char *formatted_command_json = NULL; char *ns; request_t *request; va_start (args, command_json); if (command_json) { formatted_command_json = bson_strdupv_printf (command_json, args); } va_end (args); ns = bson_strdup_printf ("%s.$cmd", database_name); request = (request_t *) q_get (rs->q, rs->request_timeout_msec); if (request && ! request_matches_query (request, ns, flags, 0, 1, formatted_command_json, NULL, true)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_rs_receives_insert -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not an insert matching ns, flags, * and doc_json. * *-------------------------------------------------------------------------- */ request_t * mock_rs_receives_insert (mock_rs_t *rs, const char *ns, mongoc_insert_flags_t flags, const char *doc_json) { request_t *request; request = (request_t *) q_get (rs->q, rs->request_timeout_msec); if (request && !request_matches_insert (request, ns, flags, doc_json)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_rs_receives_getmore -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not a getmore matching n_return * and cursor_id. * *-------------------------------------------------------------------------- */ request_t * mock_rs_receives_getmore (mock_rs_t *rs, const char *ns, uint32_t n_return, int64_t cursor_id) { request_t *request; request = (request_t *) q_get (rs->q, rs->request_timeout_msec); if (request && !request_matches_getmore (request, ns, n_return, cursor_id)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_rs_hangs_up -- * * Hang up on a client request. * * Returns: * None. * * Side effects: * Causes a network error on the client side. * *-------------------------------------------------------------------------- */ void mock_rs_hangs_up (request_t *request) { mock_server_hangs_up (request); } /*-------------------------------------------------------------------------- * * mock_rs_receives_kill_cursors -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Real-life OP_KILLCURSORS can take multiple ids, but that is * not yet supported here. * * Returns: * A request you must request_destroy, or NULL if the request * does not match. * * Side effects: * Logs if the current request is not an OP_KILLCURSORS with the * expected cursor_id. * *-------------------------------------------------------------------------- */ request_t * mock_rs_receives_kill_cursors (mock_rs_t *rs, int64_t cursor_id) { request_t *request; request = (request_t *) q_get (rs->q, rs->request_timeout_msec); if (request && !request_matches_kill_cursors (request, cursor_id)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_rs_replies -- * * Respond to a client request. * * Returns: * None. * * Side effects: * Sends an OP_REPLY to the client. * *-------------------------------------------------------------------------- */ void mock_rs_replies (request_t *request, uint32_t flags, int64_t cursor_id, int32_t starting_from, int32_t number_returned, const char *docs_json) { mock_server_replies (request, flags, cursor_id, starting_from, number_returned, docs_json); } static mongoc_server_description_type_t _mock_rs_server_type (mock_rs_t *rs, uint16_t port) { int i; if (rs->primary && port == mock_server_get_port (rs->primary)) { return MONGOC_SERVER_RS_PRIMARY; } for (i = 0; i < rs->secondaries.len; i++) { if (port == mock_server_get_port (get_server (&rs->secondaries, i))) { return MONGOC_SERVER_RS_SECONDARY; } } for (i = 0; i < rs->arbiters.len; i++) { if (port == mock_server_get_port (get_server (&rs->arbiters, i))) { return MONGOC_SERVER_RS_ARBITER; } } return MONGOC_SERVER_UNKNOWN; } /*-------------------------------------------------------------------------- * * mock_rs_replies_simple -- * * Respond to a client request. * * Returns: * None. * * Side effects: * Sends an OP_REPLY to the client. * *-------------------------------------------------------------------------- */ void mock_rs_replies_simple (request_t *request, const char *docs_json) { mock_rs_replies (request, 0, 0, 0, 1, docs_json); } /*-------------------------------------------------------------------------- * * mock_rs_replies_to_find -- * * Receive an OP_QUERY or "find" command and reply appropriately. * * Returns: * None. * * Side effects: * Very roughly validates the query or "find" command or aborts. * The intent is not to test the driver's query or find command * implementation here, see _test_kill_cursors for example use. * *-------------------------------------------------------------------------- */ void mock_rs_replies_to_find (request_t *request, mongoc_query_flags_t flags, int64_t cursor_id, int32_t number_returned, const char *ns, const char *reply_json, bool is_command) { mock_server_replies_to_find (request, flags, cursor_id, number_returned, ns, reply_json, is_command); } /*-------------------------------------------------------------------------- * * mock_rs_request_is_to_primary -- * * Check that the request is non-NULL and sent to a * primary in this replica set. * * Returns: * True if so. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool mock_rs_request_is_to_primary (mock_rs_t *rs, request_t *request) { assert (request); return MONGOC_SERVER_RS_PRIMARY == _mock_rs_server_type ( rs, request_get_server_port (request)); } /*-------------------------------------------------------------------------- * * mock_rs_request_is_to_secondary -- * * Check that the request is non-NULL and sent to a * secondary in this replica set. * * Returns: * True if so. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool mock_rs_request_is_to_secondary (mock_rs_t *rs, request_t *request) { assert (request); return MONGOC_SERVER_RS_SECONDARY == _mock_rs_server_type ( rs, request_get_server_port (request)); } /*-------------------------------------------------------------------------- * * mock_rs_destroy -- * * Free a mock_rs_t. * * Returns: * None. * * Side effects: * Destroys each member mock_server_t, closes sockets, joins threads. * *-------------------------------------------------------------------------- */ void mock_rs_destroy (mock_rs_t *rs) { int i; for (i = 0; i < rs->servers.len; i++) { mock_server_destroy (get_server (&rs->servers, i)); } _mongoc_array_destroy (&rs->secondaries); _mongoc_array_destroy (&rs->arbiters); _mongoc_array_destroy (&rs->servers); bson_free (rs->hosts_str); mongoc_uri_destroy (rs->uri); q_destroy (rs->q); bson_free (rs); } libmongoc-1.3.1/tests/mock_server/mock-rs.h000066400000000000000000000071631264720626300207110ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MOCK_RS_H #define MOCK_RS_H #include "mongoc.h" #include "mock-server.h" typedef struct _mock_rs_t mock_rs_t; mock_rs_t *mock_rs_with_autoismaster (int32_t max_wire_version, bool has_primary, int n_secondaries, int n_arbiters); void mock_rs_set_verbose (mock_rs_t *rs, bool verbose); int64_t mock_rs_get_request_timeout_msec (mock_rs_t *rs); void mock_rs_set_request_timeout_msec (mock_rs_t *rs, int64_t request_timeout_msec); void mock_rs_run (mock_rs_t *rs); const mongoc_uri_t *mock_rs_get_uri (mock_rs_t *rs); request_t *mock_rs_receives_request (mock_rs_t *rs); request_t *mock_rs_receives_query (mock_rs_t *rs, const char *ns, mongoc_query_flags_t flags, uint32_t skip, uint32_t n_return, const char *query_json, const char *fields_json); request_t *mock_rs_receives_command (mock_rs_t *rs, const char *database_name, mongoc_query_flags_t flags, const char *command_json, ...); request_t *mock_rs_receives_insert (mock_rs_t *rs, const char *ns, mongoc_insert_flags_t flags, const char *doc_json); request_t *mock_rs_receives_getmore (mock_rs_t *rs, const char *ns, uint32_t n_return, int64_t cursor_id); request_t *mock_rs_receives_kill_cursors (mock_rs_t *rs, int64_t cursor_id); void mock_rs_replies (request_t *request, uint32_t flags, int64_t cursor_id, int32_t starting_from, int32_t number_returned, const char *docs_json); void mock_rs_replies_simple (request_t *request, const char *docs_json); void mock_rs_replies_to_find (request_t *request, mongoc_query_flags_t flags, int64_t cursor_id, int32_t number_returned, const char *ns, const char *reply_json, bool is_command); void mock_rs_hangs_up (request_t *request); bool mock_rs_request_is_to_primary (mock_rs_t *rs, request_t *request); bool mock_rs_request_is_to_secondary (mock_rs_t *rs, request_t *request); void mock_rs_destroy (mock_rs_t *rs); #endif //MOCK_RS_H libmongoc-1.3.1/tests/mock_server/mock-server.c000066400000000000000000001304541264720626300215660ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc.h" #include "mongoc-buffer-private.h" #include "mongoc-rpc-private.h" #include "mongoc-socket-private.h" #include "mongoc-thread-private.h" #include "mongoc-trace.h" #include "mongoc-util-private.h" #include "sync-queue.h" #include "mock-server.h" #include "../test-conveniences.h" #include "../test-libmongoc.h" #define TIMEOUT 100 struct _mock_server_t { bool running; bool stopped; bool verbose; bool rand_delay; int64_t request_timeout_msec; uint16_t port; mongoc_socket_t *sock; char *uri_str; mongoc_uri_t *uri; mongoc_thread_t main_thread; mongoc_cond_t cond; mongoc_mutex_t mutex; int32_t last_response_id; mongoc_array_t worker_threads; sync_queue_t *q; mongoc_array_t autoresponders; int last_autoresponder_id; int64_t start_time; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t *ssl_opts; #endif }; struct _autoresponder_handle_t { autoresponder_t responder; void *data; destructor_t destructor; int id; }; static void *main_thread (void *data); static void *worker_thread (void *data); void autoresponder_handle_destroy (autoresponder_handle_t *handle); static uint16_t get_port (mongoc_socket_t *sock); /*-------------------------------------------------------------------------- * * mock_server_new -- * * Get a new mock_server_t. Call mock_server_run to start it, * then mock_server_get_uri to connect. * * This server does not autorespond to "ismaster". * * Returns: * A server you must mock_server_destroy. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mock_server_t * mock_server_new () { mock_server_t *server = (mock_server_t *)bson_malloc0 (sizeof (mock_server_t)); server->request_timeout_msec = 10 * 1000; _mongoc_array_init (&server->autoresponders, sizeof (autoresponder_handle_t)); _mongoc_array_init (&server->worker_threads, sizeof (mongoc_thread_t)); mongoc_cond_init (&server->cond); mongoc_mutex_init (&server->mutex); server->q = q_new (); server->start_time = bson_get_monotonic_time (); if (test_framework_getenv_bool ("MONGOC_TEST_SERVER_VERBOSE")) { server->verbose = true; } return server; } /*-------------------------------------------------------------------------- * * mock_server_with_autoismaster -- * * A new mock_server_t that autoresponds to ismaster. Call * mock_server_run to start it, then mock_server_get_uri to * connect. * * Returns: * A server you must mock_server_destroy. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mock_server_t * mock_server_with_autoismaster (int32_t max_wire_version) { mock_server_t *server = mock_server_new (); /* TODO: max_wire_version 0 is special */ char *ismaster = bson_strdup_printf ("{'ok': 1.0," " 'ismaster': true," " 'minWireVersion': 0," " 'maxWireVersion': %d}", max_wire_version); mock_server_auto_ismaster (server, ismaster); bson_free (ismaster); return server; } static bool hangup (request_t *request, void *ctx) { mock_server_hangs_up (request); request_destroy (request); return true; } /*-------------------------------------------------------------------------- * * mock_server_down -- * * A new mock_server_t hangs up. Call mock_server_run to start it, * then mock_server_get_uri to connect. * * Returns: * A server you must mock_server_destroy. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mock_server_t * mock_server_down (void) { mock_server_t *server = mock_server_new (); mock_server_autoresponds (server, hangup, NULL, NULL); return server; } #ifdef MONGOC_ENABLE_SSL /*-------------------------------------------------------------------------- * * mock_server_set_ssl_opts -- * * Set server-side SSL options before calling mock_server_run. * * opts should be valid for server's lifetime. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mock_server_set_ssl_opts (mock_server_t *server, mongoc_ssl_opt_t *opts) { server->ssl_opts = opts; } #endif /*-------------------------------------------------------------------------- * * mock_server_run -- * * Start listening on an unused port. After this, call * mock_server_get_uri to connect. * * Returns: * The bound port. * * Side effects: * The server's port and URI are set. * *-------------------------------------------------------------------------- */ uint16_t mock_server_run (mock_server_t *server) { mongoc_socket_t *ssock; struct sockaddr_in bind_addr; int optval; uint16_t bound_port; MONGOC_INFO ("Starting mock server on port %d.", server->port); ssock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); if (!ssock) { perror ("Failed to create socket."); return 0; } optval = 1; mongoc_socket_setsockopt (ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); memset (&bind_addr, 0, sizeof bind_addr); bind_addr.sin_family = AF_INET; bind_addr.sin_addr.s_addr = htonl (INADDR_ANY); /* bind to unused port */ bind_addr.sin_port = htons (0); if (-1 == mongoc_socket_bind (ssock, (struct sockaddr *) &bind_addr, sizeof bind_addr)) { perror ("Failed to bind socket"); return 0; } if (-1 == mongoc_socket_listen (ssock, 10)) { perror ("Failed to put socket into listen mode"); return 0; } bound_port = get_port (ssock); if (!bound_port) { perror ("Failed to get bound port number"); return 0; } mongoc_mutex_lock (&server->mutex); server->sock = ssock; server->port = bound_port; /* TODO: configurable timeouts, perhaps from env */ server->uri_str = bson_strdup_printf ( "mongodb://127.0.0.1:%hu/?serverselectiontimeoutms=10000&" "sockettimeoutms=10000", bound_port); server->uri = mongoc_uri_new (server->uri_str); mongoc_thread_create (&server->main_thread, main_thread, (void *) server); /* wait for main thread to start */ mongoc_cond_wait (&server->cond, &server->mutex); mongoc_mutex_unlock (&server->mutex); if (mock_server_get_verbose (server)) { fprintf (stderr, "listening on port %hu\n", bound_port); fflush (stdout); } return (uint16_t) bound_port; } /*-------------------------------------------------------------------------- * * mock_server_autoresponds -- * * Respond to matching requests. "data" is passed to the responder * callback, and passed to "destructor" when the autoresponder is * destroyed. * * Responders are run most-recently-added-first until one returns * true to indicate it has handled the request. If none handles it, * the request is enqueued until a call to mock_server_receives_*. * * Autoresponders must call request_destroy after handling a * request. * * Returns: * An id for mock_server_remove_autoresponder. * * Side effects: * If a matching request is enqueued, pop it and respond. * *-------------------------------------------------------------------------- */ int mock_server_autoresponds (mock_server_t *server, autoresponder_t responder, void *data, destructor_t destructor) { autoresponder_handle_t handle = { responder, data, destructor }; int id; mongoc_mutex_lock (&server->mutex); id = handle.id = server->last_autoresponder_id++; /* TODO: peek and see if a matching request is enqueued */ _mongoc_array_append_val (&server->autoresponders, handle); mongoc_mutex_unlock (&server->mutex); return id; } /*-------------------------------------------------------------------------- * * mock_server_remove_autoresponder -- * * Remove a responder callback. Pass in the id returned by * mock_server_autoresponds. * * Returns: * None. * * Side effects: * The responder's destructor is called on its "data" pointer. * *-------------------------------------------------------------------------- */ void mock_server_remove_autoresponder (mock_server_t *server, int id) { size_t i; autoresponder_handle_t *handles; mongoc_mutex_lock (&server->mutex); handles = (autoresponder_handle_t *) server->autoresponders.data; for (i = 0; i < server->autoresponders.len; i++) { if (handles[i].id == id) { /* left-shift everyone after */ server->autoresponders.len--; for (; i < server->autoresponders.len; i++) { handles[i] = handles[i + 1]; } autoresponder_handle_destroy (handles); break; } } mongoc_mutex_unlock (&server->mutex); } static bool auto_ismaster (request_t *request, void *data) { const char *response_json = (const char *) data; char *quotes_replaced; bson_t response; bson_error_t error; if (!request->is_command || strcasecmp (request->command_name, "ismaster")) { return false; } quotes_replaced = single_quotes_to_double (response_json); if (!bson_init_from_json (&response, quotes_replaced, -1, &error)) { fprintf (stderr, "%s\n", error.message); fflush (stderr); abort (); } if (mock_server_get_rand_delay (request->server)) { _mongoc_usleep ((int64_t) (rand () % 10) * 1000); } mock_server_replies (request, MONGOC_REPLY_NONE, 0, 0, 1, response_json); bson_destroy (&response); bson_free (quotes_replaced); request_destroy (request); return true; } /*-------------------------------------------------------------------------- * * mock_server_auto_ismaster -- * * Autorespond to "ismaster" with the provided document. * * Returns: * An id for mock_server_remove_autoresponder. * * Side effects: * If a matching request is enqueued, pop it and respond. * *-------------------------------------------------------------------------- */ int mock_server_auto_ismaster (mock_server_t *server, const char *response_json, ...) { char *formatted_response_json; va_list args; va_start (args, response_json); formatted_response_json = bson_strdupv_printf (response_json, args); va_end (args); return mock_server_autoresponds (server, auto_ismaster, (void *) formatted_response_json, bson_free); } /*-------------------------------------------------------------------------- * * mock_server_get_uri -- * * Call after mock_server_run to get the connection string. * * Returns: * A const URI. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_uri_t * mock_server_get_uri (mock_server_t *server) { mongoc_uri_t *uri; mongoc_mutex_lock (&server->mutex); uri = server->uri; mongoc_mutex_unlock (&server->mutex); return uri; } /*-------------------------------------------------------------------------- * * mock_server_get_host_and_port -- * * Call after mock_server_run to get the server's "host:port". * * Returns: * A const string. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const char * mock_server_get_host_and_port (mock_server_t *server) { const mongoc_uri_t *uri; uri = mock_server_get_uri (server); assert (uri); /* must call after mock_server_run */ return (mongoc_uri_get_hosts (uri))->host_and_port; } /*-------------------------------------------------------------------------- * * mock_server_get_port -- * * Call after mock_server_run to get the server's listening port. * * Returns: * A port number. * * Side effects: * None. * *-------------------------------------------------------------------------- */ uint16_t mock_server_get_port (mock_server_t *server) { return server->port; } /*-------------------------------------------------------------------------- * * mock_server_get_verbose -- * * Is the server set to log during normal operation? * *-------------------------------------------------------------------------- */ bool mock_server_get_verbose (mock_server_t *server) { bool verbose; mongoc_mutex_lock (&server->mutex); verbose = server->verbose; mongoc_mutex_unlock (&server->mutex); return verbose; } /*-------------------------------------------------------------------------- * * mock_server_set_verbose -- * * Tell the server whether to log during normal operation. * *-------------------------------------------------------------------------- */ void mock_server_set_verbose (mock_server_t *server, bool verbose) { mongoc_mutex_lock (&server->mutex); server->verbose = verbose; mongoc_mutex_unlock (&server->mutex); } /*-------------------------------------------------------------------------- * * mock_server_get_request_timeout_msec -- * * How long mock_server_receives_* functions wait for a client * request before giving up and returning NULL. * *-------------------------------------------------------------------------- */ int64_t mock_server_get_request_timeout_msec (mock_server_t *server) { int64_t request_timeout_msec; mongoc_mutex_lock (&server->mutex); request_timeout_msec = server->request_timeout_msec; mongoc_mutex_unlock (&server->mutex); return request_timeout_msec; } /*-------------------------------------------------------------------------- * * mock_server_set_request_timeout_msec -- * * How long mock_server_receives_* functions wait for a client * request before giving up and returning NULL. * *-------------------------------------------------------------------------- */ void mock_server_set_request_timeout_msec (mock_server_t *server, int64_t request_timeout_msec) { mongoc_mutex_lock (&server->mutex); server->request_timeout_msec = request_timeout_msec; mongoc_mutex_unlock (&server->mutex); } /*-------------------------------------------------------------------------- * * mock_server_get_rand_delay -- * * Does the server delay a random duration before responding? * *-------------------------------------------------------------------------- */ bool mock_server_get_rand_delay (mock_server_t *server) { bool rand_delay; mongoc_mutex_lock (&server->mutex); rand_delay = server->rand_delay; mongoc_mutex_unlock (&server->mutex); return rand_delay; } /*-------------------------------------------------------------------------- * * mock_server_set_rand_delay -- * * Whether to delay a random duration before responding. * *-------------------------------------------------------------------------- */ void mock_server_set_rand_delay (mock_server_t *server, bool rand_delay) { mongoc_mutex_lock (&server->mutex); server->rand_delay = rand_delay; mongoc_mutex_unlock (&server->mutex); } /*-------------------------------------------------------------------------- * * mock_server_set_rand_delay -- * * Whether to delay a random duration before responding. * *-------------------------------------------------------------------------- */ double mock_server_get_uptime_sec (mock_server_t *server) { double uptime; mongoc_mutex_lock (&server->mutex); uptime = (bson_get_monotonic_time () - server->start_time) / 1e6; mongoc_mutex_unlock (&server->mutex); return uptime; } sync_queue_t * mock_server_get_queue (mock_server_t *server) { sync_queue_t *q; mongoc_mutex_lock (&server->mutex); q = server->q; mongoc_mutex_unlock (&server->mutex); return q; } request_t * mock_server_receives_request (mock_server_t *server) { sync_queue_t *q; q = mock_server_get_queue (server); return (request_t *) q_get (q, server->request_timeout_msec); } /*-------------------------------------------------------------------------- * * mock_server_receives_command -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not a command matching * database_name, command_name, and command_json. * *-------------------------------------------------------------------------- */ request_t * mock_server_receives_command (mock_server_t *server, const char *database_name, mongoc_query_flags_t flags, const char *command_json, ...) { va_list args; char *formatted_command_json = NULL; char *ns; request_t *request; va_start (args, command_json); if (command_json) { formatted_command_json = bson_strdupv_printf (command_json, args); } va_end (args); ns = bson_strdup_printf ("%s.$cmd", database_name); request = mock_server_receives_request (server); if (request && !request_matches_query (request, ns, flags, 0, 1, formatted_command_json, NULL, true)) { request_destroy (request); request = NULL; } bson_free (formatted_command_json); bson_free (ns); return request; } /*-------------------------------------------------------------------------- * * mock_server_receives_ismaster -- * * Pop a client ismaster call if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the current * request is not an ismaster command. * * Side effects: * Logs if the current request is not an ismaster command. * *-------------------------------------------------------------------------- */ request_t * mock_server_receives_ismaster (mock_server_t *server) { return mock_server_receives_command ( server, "admin", MONGOC_QUERY_SLAVE_OK, "{'isMaster': 1}"); } /*-------------------------------------------------------------------------- * * mock_server_receives_gle -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not getLastError. * *-------------------------------------------------------------------------- */ request_t * mock_server_receives_gle (mock_server_t *server, const char *database_name) { return mock_server_receives_command (server, database_name, MONGOC_QUERY_NONE, "{'getLastError': 1}"); } /*-------------------------------------------------------------------------- * * mock_server_receives_query -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not a query matching ns, flags, * skip, n_return, query_json, and fields_json. * *-------------------------------------------------------------------------- */ request_t * mock_server_receives_query (mock_server_t *server, const char *ns, mongoc_query_flags_t flags, uint32_t skip, uint32_t n_return, const char *query_json, const char *fields_json) { request_t *request; request = mock_server_receives_request (server); if (request && !request_matches_query (request, ns, flags, skip, n_return, query_json, fields_json, false)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_server_receives_insert -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not an insert matching ns, flags, * and doc_json. * *-------------------------------------------------------------------------- */ request_t * mock_server_receives_insert (mock_server_t *server, const char *ns, mongoc_insert_flags_t flags, const char *doc_json) { request_t *request; request = mock_server_receives_request (server); if (request && !request_matches_insert (request, ns, flags, doc_json)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_server_receives_bulk_insert -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not an insert matching ns and flags, * with "n" documents. * *-------------------------------------------------------------------------- */ request_t * mock_server_receives_bulk_insert (mock_server_t *server, const char *ns, mongoc_insert_flags_t flags, int n) { request_t *request; request = mock_server_receives_request (server); if (request && !request_matches_bulk_insert (request, ns, flags, n)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_server_receives_update -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not an update matching ns, flags, * selector_json, and update_json. * *-------------------------------------------------------------------------- */ request_t * mock_server_receives_update (mock_server_t *server, const char *ns, mongoc_update_flags_t flags, const char *selector_json, const char *update_json) { request_t *request; request = mock_server_receives_request (server); if (request && !request_matches_update (request, ns, flags, selector_json, update_json)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_server_receives_delete -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not a delete matching ns, flags, * and selector_json. * *-------------------------------------------------------------------------- */ request_t * mock_server_receives_delete (mock_server_t *server, const char *ns, mongoc_remove_flags_t flags, const char *selector_json) { request_t *request; request = mock_server_receives_request (server); if (request && !request_matches_delete (request, ns, flags, selector_json)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_server_receives_getmore -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Returns: * A request you must request_destroy, or NULL if the request does * not match. * * Side effects: * Logs if the current request is not a getmore matching n_return * and cursor_id. * *-------------------------------------------------------------------------- */ request_t * mock_server_receives_getmore (mock_server_t *server, const char *ns, uint32_t n_return, int64_t cursor_id) { request_t *request; request = mock_server_receives_request (server); if (request && !request_matches_getmore (request, ns, n_return, cursor_id)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_server_receives_kill_cursors -- * * Pop a client request if one is enqueued, or wait up to * request_timeout_ms for the client to send a request. * * Real-life OP_KILLCURSORS can take multiple ids, but that is * not yet supported here. * * Returns: * A request you must request_destroy, or NULL if the request * does not match. * * Side effects: * Logs if the current request is not an OP_KILLCURSORS with the * expected cursor_id. * *-------------------------------------------------------------------------- */ request_t *mock_server_receives_kill_cursors (mock_server_t *server, int64_t cursor_id) { request_t *request; request = mock_server_receives_request (server); if (request && !request_matches_kill_cursors (request, cursor_id)) { request_destroy (request); return NULL; } return request; } /*-------------------------------------------------------------------------- * * mock_server_hangs_up -- * * Hang up on a client request. * * Returns: * None. * * Side effects: * Causes a network error on the client side. * *-------------------------------------------------------------------------- */ void mock_server_hangs_up (request_t *request) { if (mock_server_get_verbose (request->server)) { printf ("%5.2f %hu <- %hu \thang up!\n", mock_server_get_uptime_sec (request->server), request->client_port, request_get_server_port (request)); fflush (stdout); } mongoc_stream_close (request->client); } /*-------------------------------------------------------------------------- * * mock_server_resets -- * * Forcefully reset a connection from the client. * * Returns: * None. * * Side effects: * Causes ECONNRESET on the client side. * *-------------------------------------------------------------------------- */ void mock_server_resets (request_t *request) { struct linger no_linger; no_linger.l_onoff = 1; no_linger.l_linger = 0; if (mock_server_get_verbose (request->server)) { printf ("%5.2f %hu <- %hu \treset!\n", mock_server_get_uptime_sec (request->server), request->client_port, request_get_server_port (request)); fflush (stdout); } /* send RST packet to client */ mongoc_stream_setsockopt (request->client, SOL_SOCKET, SO_LINGER, &no_linger, sizeof no_linger); mongoc_stream_close (request->client); } /*-------------------------------------------------------------------------- * * mock_server_replies -- * * Respond to a client request. * * Returns: * None. * * Side effects: * Sends an OP_REPLY to the client. * *-------------------------------------------------------------------------- */ void mock_server_replies (request_t *request, mongoc_reply_flags_t flags, int64_t cursor_id, int32_t starting_from, int32_t number_returned, const char *docs_json) { char *quotes_replaced = single_quotes_to_double (docs_json); bson_t doc; bson_error_t error; bool r; assert (request); r = bson_init_from_json (&doc, quotes_replaced, -1, &error); if (!r) { MONGOC_WARNING ("%s", error.message); return; } mock_server_reply_multi (request, flags, &doc, 1, cursor_id); bson_destroy (&doc); bson_free (quotes_replaced); } /*-------------------------------------------------------------------------- * * mock_server_replies_simple -- * * Respond to a client request. * * Returns: * None. * * Side effects: * Sends an OP_REPLY to the client. * *-------------------------------------------------------------------------- */ void mock_server_replies_simple (request_t *request, const char *docs_json) { mock_server_replies (request, 0, 0, 0, 1, docs_json); } /*-------------------------------------------------------------------------- * * mock_server_replies_to_find -- * * Receive an OP_QUERY or "find" command and reply appropriately. * * Returns: * None. * * Side effects: * Very roughly validates the query or "find" command or aborts. * The intent is not to test the driver's query or find command * implementation here, see _test_kill_cursors for example use. * *-------------------------------------------------------------------------- */ void mock_server_replies_to_find (request_t *request, mongoc_query_flags_t flags, int64_t cursor_id, int32_t number_returned, const char *ns, const char *reply_json, bool is_command) { char *find_reply; char db[MONGOC_NAMESPACE_MAX]; _mongoc_get_db_name (ns, db); /* minimal validation, we're not testing query / find cmd here */ if (request->is_command && !is_command) { MONGOC_ERROR ("expected query, got command"); abort (); } if (!request->is_command && is_command) { MONGOC_ERROR ("expected command, got query"); abort (); } if (!request_matches_flags (request, flags)) { abort (); } if (is_command) { find_reply = bson_strdup_printf ( "{'ok': 1," " 'cursor': {" " 'id': {'$numberLong': '%" PRId64 "'}," " 'ns': '%s'," " 'firstBatch': [%s]}}", cursor_id, ns, reply_json); mock_server_replies_simple (request, find_reply); bson_free (find_reply); } else { mock_server_replies (request, MONGOC_REPLY_NONE, cursor_id, 0, number_returned, reply_json); } } /*-------------------------------------------------------------------------- * * mock_server_destroy -- * * Free a mock_server_t. * * Returns: * None. * * Side effects: * Closes sockets, joins threads, and calls destructors passed * to mock_server_autoresponds. * *-------------------------------------------------------------------------- */ void mock_server_destroy (mock_server_t *server) { size_t i; autoresponder_handle_t *handle; int64_t deadline = bson_get_monotonic_time () + 10 * 1000 * 1000; request_t *request; mongoc_mutex_lock (&server->mutex); if (server->running) { server->stopped = true; } mongoc_mutex_unlock (&server->mutex); while (bson_get_monotonic_time () <= deadline) { /* wait 10 seconds */ mongoc_mutex_lock (&server->mutex); if (!server->running) { mongoc_mutex_unlock (&server->mutex); break; } mongoc_mutex_unlock (&server->mutex); _mongoc_usleep (1000); } mongoc_mutex_lock (&server->mutex); if (server->running) { fprintf (stderr, "server still running after timeout\n"); fflush (stderr); abort (); } mongoc_mutex_unlock (&server->mutex); mongoc_thread_join (server->main_thread); _mongoc_array_destroy (&server->worker_threads); for (i = 0; i < server->autoresponders.len; i++) { handle = &_mongoc_array_index (&server->autoresponders, autoresponder_handle_t, i); autoresponder_handle_destroy (handle); } _mongoc_array_destroy (&server->autoresponders); mongoc_cond_destroy (&server->cond); mongoc_mutex_unlock (&server->mutex); mongoc_mutex_destroy (&server->mutex); mongoc_socket_destroy (server->sock); bson_free (server->uri_str); mongoc_uri_destroy (server->uri); while ((request = (request_t *) q_get_nowait (server->q))) { request_destroy (request); } q_destroy (server->q); bson_free (server); } static uint16_t get_port (mongoc_socket_t *sock) { struct sockaddr_in bound_addr = { 0 }; socklen_t addr_len = (socklen_t) sizeof bound_addr; if (mongoc_socket_getsockname (sock, (struct sockaddr *) &bound_addr, &addr_len) < 0) { perror ("Failed to get listening port number"); return 0; } return ntohs (bound_addr.sin_port); } typedef struct worker_closure_t { mock_server_t *server; mongoc_stream_t *client_stream; uint16_t port; } worker_closure_t; static void * main_thread (void *data) { mock_server_t *server = (mock_server_t *)data; mongoc_socket_t *client_sock; bool stopped; uint16_t port; mongoc_stream_t *client_stream; worker_closure_t *closure; mongoc_thread_t thread; mongoc_array_t worker_threads; size_t i; mongoc_mutex_lock (&server->mutex); server->running = true; mongoc_cond_signal (&server->cond); mongoc_mutex_unlock (&server->mutex); for (; ;) { client_sock = mongoc_socket_accept_ex ( server->sock, bson_get_monotonic_time () + TIMEOUT, &port); mongoc_mutex_lock (&server->mutex); stopped = server->stopped; mongoc_mutex_unlock (&server->mutex); if (stopped) { break; } if (client_sock) { if (mock_server_get_verbose (server)) { printf ("%5.2f %hu -> server port %hu (connected)\n", mock_server_get_uptime_sec (server), port, server->port); fflush (stdout); } client_stream = mongoc_stream_socket_new (client_sock); #ifdef MONGOC_ENABLE_SSL if (server->ssl_opts) { client_stream = mongoc_stream_tls_new (client_stream, server->ssl_opts, 0); if (!client_stream) { perror ("Failed to attach tls stream"); break; } } #endif closure = (worker_closure_t *)bson_malloc (sizeof *closure); closure->server = server; closure->client_stream = client_stream; closure->port = port; mongoc_thread_create (&thread, worker_thread, closure); mongoc_mutex_lock (&server->mutex); _mongoc_array_append_val (&server->worker_threads, thread); mongoc_mutex_unlock (&server->mutex); } } /* copy list of worker threads and join them all */ _mongoc_array_init (&worker_threads, sizeof (mongoc_thread_t)); mongoc_mutex_lock (&server->mutex); _mongoc_array_copy (&worker_threads, &server->worker_threads); mongoc_mutex_unlock (&server->mutex); for (i = 0; i < worker_threads.len; i++) { mongoc_thread_join ( _mongoc_array_index (&worker_threads, mongoc_thread_t, i)); } _mongoc_array_destroy (&worker_threads); mongoc_mutex_lock (&server->mutex); server->running = false; mongoc_mutex_unlock (&server->mutex); return NULL; } /* TODO: factor */ static void * worker_thread (void *data) { worker_closure_t *closure = (worker_closure_t *) data; mock_server_t *server = closure->server; mongoc_stream_t *client_stream = closure->client_stream; mongoc_buffer_t buffer; mongoc_rpc_t *rpc = NULL; bool handled; bson_error_t error; int32_t msg_len; bool stopped; sync_queue_t *q; request_t *request; mongoc_array_t autoresponders; ssize_t i; autoresponder_handle_t handle; ENTRY; BSON_ASSERT(closure); _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); _mongoc_array_init (&autoresponders, sizeof (autoresponder_handle_t)); again: bson_free (rpc); rpc = NULL; handled = false; mongoc_mutex_lock (&server->mutex); stopped = server->stopped; mongoc_mutex_unlock (&server->mutex); if (stopped) { goto failure; } if (_mongoc_buffer_fill (&buffer, client_stream, 4, TIMEOUT, &error) == -1) { GOTO (again); } assert (buffer.len >= 4); memcpy (&msg_len, buffer.data + buffer.off, 4); msg_len = BSON_UINT32_FROM_LE (msg_len); if (msg_len < 16) { MONGOC_WARNING ("No data"); GOTO (failure); } if (_mongoc_buffer_fill (&buffer, client_stream, (size_t) msg_len, -1, &error) == -1) { MONGOC_WARNING ("%s():%d: %s", BSON_FUNC, __LINE__, error.message); GOTO (failure); } assert (buffer.len >= (unsigned) msg_len); /* copies message from buffer */ request = request_new (&buffer, msg_len, server, client_stream, closure->port); mongoc_mutex_lock (&server->mutex); _mongoc_array_copy (&autoresponders, &server->autoresponders); mongoc_mutex_unlock (&server->mutex); if (mock_server_get_verbose (server)) { printf ("%5.2f %hu -> %hu %s\n", mock_server_get_uptime_sec (server), closure->port, server->port, request->as_str); fflush (stdout); } /* run responders most-recently-added-first */ for (i = server->autoresponders.len - 1; i >= 0; i--) { handle = _mongoc_array_index (&server->autoresponders, autoresponder_handle_t, i); if (handle.responder (request, handle.data)) { handled = true; /* responder should destroy the request */ request = NULL; break; } } if (!handled) { q = mock_server_get_queue (server); q_put (q, (void *) request); request = NULL; } memmove (buffer.data, buffer.data + buffer.off + msg_len, buffer.len - msg_len); buffer.off = 0; buffer.len -= msg_len; GOTO (again); failure: _mongoc_array_destroy (&autoresponders); _mongoc_buffer_destroy (&buffer); mongoc_stream_close (client_stream); mongoc_stream_destroy (client_stream); bson_free (rpc); bson_free (closure); _mongoc_buffer_destroy (&buffer); RETURN (NULL); } void mock_server_reply_multi (request_t *request, mongoc_reply_flags_t flags, const bson_t *docs, int n_docs, int64_t cursor_id) { const mongoc_rpc_t *request_rpc; mock_server_t *server; mongoc_stream_t *client; char *doc_json; bson_string_t *docs_json; mongoc_iovec_t *iov; mongoc_array_t ar; mongoc_rpc_t r = {{ 0 }}; size_t expected = 0; ssize_t n_written; int iovcnt; int i; uint8_t *buf; uint8_t *ptr; size_t len; BSON_ASSERT (request); BSON_ASSERT (docs); request_rpc = &request->request_rpc; server = request->server; client = request->client; docs_json = bson_string_new (""); for (i = 0; i < n_docs; i++) { doc_json = bson_as_json (&docs[i], NULL); bson_string_append (docs_json, doc_json); bson_free (doc_json); if (i < n_docs - 1) { bson_string_append (docs_json, ", "); } } if (mock_server_get_verbose (request->server)) { printf ("%5.2f %hu <- %hu \t%s\n", mock_server_get_uptime_sec (request->server), request->client_port, mock_server_get_port (request->server), docs_json->str); fflush (stdout); } len = 0; for (i = 0; i < n_docs; i++) { len += docs[i].len; } ptr = buf = bson_malloc (len); for (i = 0; i < n_docs; i++) { memcpy (ptr, bson_get_data (&docs[i]), docs[i].len); ptr += docs[i].len; } _mongoc_array_init (&ar, sizeof (mongoc_iovec_t)); if (!(request->opcode == MONGOC_OPCODE_QUERY && request_rpc->query.flags & MONGOC_QUERY_EXHAUST)) { server->last_response_id++; } mongoc_mutex_lock (&server->mutex); r.reply.request_id = server->last_response_id; mongoc_mutex_unlock (&server->mutex); r.reply.msg_len = 0; r.reply.response_to = request_rpc->header.request_id; r.reply.opcode = MONGOC_OPCODE_REPLY; r.reply.flags = flags; r.reply.cursor_id = cursor_id; r.reply.start_from = 0; r.reply.n_returned = 1; r.reply.documents = buf; r.reply.documents_len = (uint32_t)len; _mongoc_rpc_gather (&r, &ar); _mongoc_rpc_swab_to_le (&r); iov = (mongoc_iovec_t *)ar.data; iovcnt = (int) ar.len; for (i = 0; i < iovcnt; i++) { expected += iov[i].iov_len; } n_written = mongoc_stream_writev (client, iov, (size_t) iovcnt, -1); assert (n_written == expected); bson_string_free (docs_json, true); _mongoc_array_destroy (&ar); bson_free (buf); } void autoresponder_handle_destroy (autoresponder_handle_t *handle) { if (handle->destructor) { handle->destructor (handle->data); } } libmongoc-1.3.1/tests/mock_server/mock-server.h000066400000000000000000000142641264720626300215730ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MOCK_SERVER_H #define MOCK_SERVER_H #include #include "mongoc-uri.h" #ifdef MONGOC_ENABLE_SSL #include "mongoc-ssl.h" #endif #include "request.h" typedef struct _mock_server_t mock_server_t; typedef struct _autoresponder_handle_t autoresponder_handle_t; typedef bool (*autoresponder_t) (request_t *request, void *data); typedef void (*destructor_t) (void *data); mock_server_t *mock_server_new (); mock_server_t *mock_server_with_autoismaster (int32_t max_wire_version); mock_server_t *mock_server_down (void); int mock_server_autoresponds (mock_server_t *server, autoresponder_t responder, void *data, destructor_t destructor); void mock_server_remove_autoresponder (mock_server_t *server, int id); int mock_server_auto_ismaster (mock_server_t *server, const char *response_json, ...); #ifdef MONGOC_ENABLE_SSL void mock_server_set_ssl_opts (mock_server_t *server, mongoc_ssl_opt_t *opts); #endif uint16_t mock_server_run (mock_server_t *server); const mongoc_uri_t *mock_server_get_uri (mock_server_t *server); const char *mock_server_get_host_and_port (mock_server_t *server); uint16_t mock_server_get_port (mock_server_t *server); bool mock_server_get_verbose (mock_server_t *server); void mock_server_set_verbose (mock_server_t *server, bool verbose); int64_t mock_server_get_request_timeout_msec (mock_server_t *server); void mock_server_set_request_timeout_msec (mock_server_t *server, int64_t request_timeout_msec); bool mock_server_get_rand_delay (mock_server_t *server); void mock_server_set_rand_delay (mock_server_t *server, bool rand_delay); double mock_server_get_uptime_sec (mock_server_t *server); request_t *mock_server_receives_command (mock_server_t *server, const char *database_name, mongoc_query_flags_t flags, const char *command_json, ...); request_t *mock_server_receives_ismaster (mock_server_t *server); request_t *mock_server_receives_gle (mock_server_t *server, const char *database_name); request_t *mock_server_receives_query (mock_server_t *server, const char *ns, mongoc_query_flags_t flags, uint32_t skip, uint32_t n_return, const char *query_json, const char *fields_json); request_t *mock_server_receives_insert (mock_server_t *server, const char *ns, mongoc_insert_flags_t flags, const char *doc_json); request_t *mock_server_receives_bulk_insert (mock_server_t *server, const char *ns, mongoc_insert_flags_t flags, int n); request_t *mock_server_receives_update (mock_server_t *server, const char *ns, mongoc_update_flags_t flags, const char *selector_json, const char *update_json); request_t * mock_server_receives_delete (mock_server_t *server, const char *ns, mongoc_remove_flags_t flags, const char *selector_json); request_t *mock_server_receives_getmore (mock_server_t *server, const char *ns, uint32_t n_return, int64_t cursor_id); request_t *mock_server_receives_kill_cursors (mock_server_t *server, int64_t cursor_id); void mock_server_hangs_up (request_t *request); void mock_server_resets (request_t *request); void mock_server_replies (request_t *request, mongoc_reply_flags_t flags, int64_t cursor_id, int32_t starting_from, int32_t number_returned, const char *docs_json); void mock_server_replies_simple (request_t *request, const char *docs_json); void mock_server_replies_to_find (request_t *request, mongoc_query_flags_t flags, int64_t cursor_id, int32_t number_returned, const char *ns, const char *reply_json, bool is_command); void mock_server_reply_multi (request_t *request, mongoc_reply_flags_t flags, const bson_t *docs, int n_docs, int64_t cursor_id); void mock_server_destroy (mock_server_t *server); #endif //MOCK_SERVER_H libmongoc-1.3.1/tests/mock_server/request.c000066400000000000000000000554571264720626300210320ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc.h" #include "mock-server.h" #include "../test-conveniences.h" #include "../TestSuite.h" static bool is_command_ns (const char *ns); static void request_from_query (request_t *request, const mongoc_rpc_t *rpc); static void request_from_insert (request_t *request, const mongoc_rpc_t *rpc); static void request_from_update (request_t *request, const mongoc_rpc_t *rpc); static void request_from_delete (request_t *request, const mongoc_rpc_t *rpc); static void request_from_killcursors (request_t *request, const mongoc_rpc_t *rpc); static void request_from_getmore (request_t *request, const mongoc_rpc_t *rpc); static char *query_flags_str (uint32_t flags); static char *insert_flags_str (uint32_t flags); static char *update_flags_str (uint32_t flags); static char *delete_flags_str (uint32_t flags); request_t * request_new (const mongoc_buffer_t *buffer, int32_t msg_len, mock_server_t *server, mongoc_stream_t *client, uint16_t client_port) { request_t *request = (request_t *)bson_malloc0 (sizeof *request); uint8_t *data; data = (uint8_t *)bson_malloc ((size_t)msg_len); memcpy (data, buffer->data + buffer->off, (size_t) msg_len); request->data = data; request->data_len = (size_t) msg_len; if (!_mongoc_rpc_scatter (&request->request_rpc, data, (size_t) msg_len)) { MONGOC_WARNING ("%s():%d: %s", BSON_FUNC, __LINE__, "Failed to scatter"); bson_free (data); bson_free (request); return NULL; } _mongoc_rpc_swab_from_le (&request->request_rpc); request->opcode = (mongoc_opcode_t) request->request_rpc.header.opcode; request->server = server; request->client = client; request->client_port = client_port; _mongoc_array_init (&request->docs, sizeof (bson_t *)); switch (request->opcode) { case MONGOC_OPCODE_QUERY: request_from_query (request, &request->request_rpc); break; case MONGOC_OPCODE_INSERT: request_from_insert (request, &request->request_rpc); break; case MONGOC_OPCODE_UPDATE: request_from_update (request, &request->request_rpc); break; case MONGOC_OPCODE_KILL_CURSORS: request_from_killcursors (request, &request->request_rpc); break; case MONGOC_OPCODE_GET_MORE: request_from_getmore (request, &request->request_rpc); break; case MONGOC_OPCODE_DELETE: request_from_delete (request, &request->request_rpc); break; case MONGOC_OPCODE_REPLY: case MONGOC_OPCODE_MSG: default: fprintf (stderr, "Unimplemented opcode %d\n", request->opcode); abort (); } return request; } const bson_t * request_get_doc (const request_t *request, int n) { return _mongoc_array_index (&request->docs, const bson_t *, n); } bool request_matches_flags (const request_t *request, mongoc_query_flags_t flags) { const mongoc_rpc_t *rpc; assert (request); rpc = &request->request_rpc; if (rpc->query.flags != flags) { MONGOC_ERROR ("request's query flags are %s, expected %s", query_flags_str (rpc->query.flags), query_flags_str (flags)); return false; } return true; } /* TODO: take file, line, function params from caller, wrap in macro */ bool request_matches_query (const request_t *request, const char *ns, mongoc_query_flags_t flags, uint32_t skip, uint32_t n_return, const char *query_json, const char *fields_json, bool is_command) { const mongoc_rpc_t *rpc; const bson_t *doc; bool n_return_equal; assert (request); rpc = &request->request_rpc; assert (request->docs.len <= 2); if (request->is_command && !is_command) { MONGOC_ERROR ("expected query, got command"); return false; } if (!request->is_command && is_command) { MONGOC_ERROR ("expected command, got query"); return false; } if (request->opcode != MONGOC_OPCODE_QUERY) { MONGOC_ERROR ("request's opcode does not match QUERY"); return false; } if (strcmp (rpc->query.collection, ns)) { MONGOC_ERROR ("request's namespace is '%s', expected '%s'", request->request_rpc.query.collection, ns); return false; } if (!request_matches_flags (request, flags)) { return false; } if (rpc->query.skip != skip) { MONGOC_ERROR ("requests's skip = %d, expected %d", rpc->query.skip, skip); return false; } n_return_equal = (rpc->query.n_return == n_return); if (! n_return_equal && abs (rpc->query.n_return) == 1) { /* quirk: commands from mongoc_client_command_simple have n_return 1, * from mongoc_topology_scanner_t have n_return -1 */ n_return_equal = abs (rpc->query.n_return) == n_return; } if (! n_return_equal) { MONGOC_ERROR ("requests's n_return = %d, expected %d", rpc->query.n_return, n_return); return false; } if (request->docs.len) { doc = request_get_doc(request, 0); } else { doc = NULL; } if (!match_json (doc, is_command, __FILE__, __LINE__, BSON_FUNC, query_json)) { /* match_json has logged the err */ return false; } if (request->docs.len > 1) { doc = request_get_doc (request, 1); } else { doc = NULL; } if (!match_json (doc, false, __FILE__, __LINE__, BSON_FUNC, fields_json)) { /* match_json has logged the err */ return false; } return true; } /* TODO: take file, line, function params from caller, wrap in macro */ bool request_matches_insert (const request_t *request, const char *ns, mongoc_insert_flags_t flags, const char *doc_json) { const mongoc_rpc_t *rpc; const bson_t *doc; assert (request); rpc = &request->request_rpc; if (request->opcode != MONGOC_OPCODE_INSERT) { MONGOC_ERROR ("request's opcode does not match INSERT"); return false; } if (strcmp (rpc->insert.collection, ns)) { MONGOC_ERROR ("insert's namespace is '%s', expected '%s'", request->request_rpc.get_more.collection, ns); return false; } if (rpc->insert.flags != flags) { MONGOC_ERROR ("request's insert flags are %s, expected %s", insert_flags_str (rpc->insert.flags), insert_flags_str (flags)); return false; } ASSERT_CMPINT ((int)request->docs.len, ==, 1); doc = request_get_doc(request, 0); if (!match_json (doc, false, __FILE__, __LINE__, BSON_FUNC, doc_json)) { return false; } return true; } /* TODO: take file, line, function params from caller, wrap in macro */ bool request_matches_bulk_insert (const request_t *request, const char *ns, mongoc_insert_flags_t flags, int n) { const mongoc_rpc_t *rpc; assert (request); rpc = &request->request_rpc; if (request->opcode != MONGOC_OPCODE_INSERT) { MONGOC_ERROR ("request's opcode does not match INSERT"); return false; } if (strcmp (rpc->insert.collection, ns)) { MONGOC_ERROR ("insert's namespace is '%s', expected '%s'", request->request_rpc.get_more.collection, ns); return false; } if (rpc->insert.flags != flags) { MONGOC_ERROR ("request's insert flags are %s, expected %s", insert_flags_str (rpc->insert.flags), insert_flags_str (flags)); return false; } if ((int)request->docs.len != n) { MONGOC_ERROR ("expected %d docs inserted, got %d", n, (int)request->docs.len); return false; } return true; } /* TODO: take file, line, function params from caller, wrap in macro */ bool request_matches_update (const request_t *request, const char *ns, mongoc_update_flags_t flags, const char *selector_json, const char *update_json) { const mongoc_rpc_t *rpc; const bson_t *doc; assert (request); rpc = &request->request_rpc; if (request->opcode != MONGOC_OPCODE_UPDATE) { MONGOC_ERROR ("request's opcode does not match UPDATE"); return false; } if (strcmp (rpc->update.collection, ns)) { MONGOC_ERROR ("update's namespace is '%s', expected '%s'", request->request_rpc.update.collection, ns); return false; } if (rpc->update.flags != flags) { MONGOC_ERROR ("request's update flags are %s, expected %s", update_flags_str (rpc->update.flags), update_flags_str (flags)); return false; } ASSERT_CMPINT ((int)request->docs.len, ==, 2); doc = request_get_doc(request, 0); if (!match_json (doc, false, __FILE__, __LINE__, BSON_FUNC, selector_json)) { return false; } doc = request_get_doc(request, 1); if (!match_json (doc, false, __FILE__, __LINE__, BSON_FUNC, update_json)) { return false; } return true; } /* TODO: take file, line, function params from caller, wrap in macro */ bool request_matches_delete (const request_t *request, const char *ns, mongoc_remove_flags_t flags, const char *selector_json) { const mongoc_rpc_t *rpc; const bson_t *doc; assert (request); rpc = &request->request_rpc; if (request->opcode != MONGOC_OPCODE_DELETE) { MONGOC_ERROR ("request's opcode does not match DELETE"); return false; } if (strcmp (rpc->delete_.collection, ns)) { MONGOC_ERROR ("delete's namespace is '%s', expected '%s'", request->request_rpc.delete_.collection, ns); return false; } if (rpc->delete_.flags != flags) { MONGOC_ERROR ("request's delete flags are %s, expected %s", delete_flags_str (rpc->delete_.flags), delete_flags_str (flags)); return false; } ASSERT_CMPINT ((int)request->docs.len, ==, 1); doc = request_get_doc(request, 0); if (!match_json (doc, false, __FILE__, __LINE__, BSON_FUNC, selector_json)) { return false; } return true; } /* TODO: take file, line, function params from caller, wrap in macro */ bool request_matches_getmore (const request_t *request, const char *ns, uint32_t n_return, int64_t cursor_id) { const mongoc_rpc_t *rpc; assert (request); rpc = &request->request_rpc; if (request->opcode != MONGOC_OPCODE_GET_MORE) { MONGOC_ERROR ("request's opcode does not match GET_MORE"); return false; } if (strcmp (rpc->get_more.collection, ns)) { MONGOC_ERROR ("request's namespace is '%s', expected '%s'", request->request_rpc.get_more.collection, ns); return false; } if (rpc->get_more.n_return != n_return) { MONGOC_ERROR ("requests's n_return = %d, expected %d", rpc->query.n_return, n_return); return false; } if (rpc->get_more.cursor_id != cursor_id) { MONGOC_ERROR ("requests's cursor_id = %" PRId64 ", expected %" PRId64, rpc->get_more.cursor_id, cursor_id); return false; } return true; } /* TODO: take file, line, function params from caller, wrap in macro */ bool request_matches_kill_cursors (const request_t *request, int64_t cursor_id) { const mongoc_rpc_t *rpc; assert (request); rpc = &request->request_rpc; if (request->opcode != MONGOC_OPCODE_KILL_CURSORS) { MONGOC_ERROR ("request's opcode does not match KILL_CURSORS"); return false; } if (rpc->kill_cursors.n_cursors != 1) { MONGOC_ERROR ("request's n_cursors is %d, expected 1", rpc->kill_cursors.n_cursors); return false; } if (rpc->kill_cursors.cursors[0] != cursor_id) { MONGOC_ERROR ("request's cursor_id %" PRId64 ", expected %" PRId64, rpc->kill_cursors.cursors[0], cursor_id); return false; } return true; } /*-------------------------------------------------------------------------- * * request_get_server_port -- * * Get the port of the server this request was sent to. * * Returns: * A port number. * * Side effects: * None. * *-------------------------------------------------------------------------- */ uint16_t request_get_server_port (request_t *request) { return mock_server_get_port (request->server); } /*-------------------------------------------------------------------------- * * request_get_client_port -- * * Get the client port this request was sent from. * * Returns: * A port number. * * Side effects: * None. * *-------------------------------------------------------------------------- */ uint16_t request_get_client_port (request_t *request) { return request->client_port; } /*-------------------------------------------------------------------------- * * request_destroy -- * * Free a request_t. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void request_destroy (request_t *request) { size_t i; bson_t *doc; for (i = 0; i < request->docs.len; i++) { doc = _mongoc_array_index (&request->docs, bson_t *, i); bson_destroy (doc); } _mongoc_array_destroy (&request->docs); bson_free (request->command_name); bson_free (request->as_str); bson_free (request->data); bson_free (request); } static bool is_command_ns (const char *ns) { size_t len = strlen (ns); const char *cmd = ".$cmd"; size_t cmd_len = strlen (cmd); return len > cmd_len && !strncmp (ns + len - cmd_len, cmd, cmd_len); } static char * query_flags_str (uint32_t flags) { int flag = 1; bson_string_t *str = bson_string_new (""); bool begun = false; if (flags == MONGOC_QUERY_NONE) { bson_string_append (str, "0"); } else { while (flag <= MONGOC_QUERY_PARTIAL) { flag <<= 1; if (flags & flag) { if (begun) { bson_string_append (str, "|"); } begun = true; switch (flag) { case MONGOC_QUERY_TAILABLE_CURSOR: bson_string_append (str, "TAILABLE"); break; case MONGOC_QUERY_SLAVE_OK: bson_string_append (str, "SLAVE_OK"); break; case MONGOC_QUERY_OPLOG_REPLAY: bson_string_append (str, "OPLOG_REPLAY"); break; case MONGOC_QUERY_NO_CURSOR_TIMEOUT: bson_string_append (str, "NO_TIMEOUT"); break; case MONGOC_QUERY_AWAIT_DATA: bson_string_append (str, "AWAIT_DATA"); break; case MONGOC_QUERY_EXHAUST: bson_string_append (str, "EXHAUST"); break; case MONGOC_QUERY_PARTIAL: bson_string_append (str, "PARTIAL"); break; case MONGOC_QUERY_NONE: default: assert (false); } } } } return bson_string_free (str, false); /* detach buffer */ } static void request_from_query (request_t *request, const mongoc_rpc_t *rpc) { int32_t len; bson_t *query; bson_t *fields; bson_iter_t iter; bson_string_t *query_as_str = bson_string_new ("OP_QUERY "); char *str; memcpy (&len, rpc->query.query, 4); len = BSON_UINT32_FROM_LE (len); query = bson_new_from_data (rpc->query.query, (size_t) len); assert (query); _mongoc_array_append_val (&request->docs, query); bson_string_append_printf (query_as_str, "%s ", rpc->query.collection); if (is_command_ns (request->request_rpc.query.collection)) { request->is_command = true; if (bson_iter_init (&iter, query) && bson_iter_next (&iter)) { request->command_name = bson_strdup (bson_iter_key (&iter)); } else { fprintf (stderr, "WARNING: no command name for %s\n", request->request_rpc.query.collection); } } str = bson_as_json (query, NULL); bson_string_append (query_as_str, str); bson_free (str); if (rpc->query.fields) { memcpy (&len, rpc->query.fields, 4); len = BSON_UINT32_FROM_LE (len); fields = bson_new_from_data (rpc->query.fields, (size_t) len); assert (fields); _mongoc_array_append_val (&request->docs, fields); str = bson_as_json (fields, NULL); bson_string_append (query_as_str, " fields="); bson_string_append (query_as_str, str); bson_free (str); } bson_string_append (query_as_str, " flags="); str = query_flags_str (rpc->query.flags); bson_string_append (query_as_str, str); bson_free (str); request->as_str = bson_string_free (query_as_str, false); } static char * insert_flags_str (uint32_t flags) { if (flags == MONGOC_INSERT_NONE) { return bson_strdup ("0"); } else { return bson_strdup ("CONTINUE_ON_ERROR"); } } static uint32_t length_prefix (void *data) { uint32_t len_le; memcpy (&len_le, data, sizeof (len_le)); return BSON_UINT32_FROM_LE (len_le); } static void request_from_insert (request_t *request, const mongoc_rpc_t *rpc) { uint8_t *pos = (uint8_t *)request->request_rpc.insert.documents->iov_base; uint8_t *end = request->data + request->data_len; bson_string_t *insert_as_str = bson_string_new("OP_INSERT"); bson_t *doc; size_t n_documents; size_t i; char *str; while (pos < end) { uint32_t len = length_prefix (pos); doc = bson_new_from_data (pos, len); assert (doc); _mongoc_array_append_val (&request->docs, doc); pos += len; } n_documents = request->docs.len; bson_string_append_printf (insert_as_str, " %d ", (int)n_documents); for (i = 0; i < n_documents; i++) { str = bson_as_json (request_get_doc (request, (int) i), NULL); assert (str); bson_string_append (insert_as_str, str); bson_free (str); if (i < n_documents - 1) { bson_string_append (insert_as_str, ", "); } } bson_string_append (insert_as_str, " flags="); str = insert_flags_str (rpc->insert.flags); bson_string_append (insert_as_str, str); bson_free (str); request->as_str = bson_string_free (insert_as_str, false); } static char * update_flags_str (uint32_t flags) { int flag = 1; bson_string_t *str = bson_string_new (""); bool begun = false; if (flags == MONGOC_UPDATE_NONE) { bson_string_append (str, "0"); } else { while (flag <= MONGOC_UPDATE_MULTI_UPDATE) { flag <<= 1; if (flags & flag) { if (begun) { bson_string_append (str, "|"); } begun = true; switch (flag) { case MONGOC_UPDATE_UPSERT: bson_string_append (str, "UPSERT"); break; case MONGOC_UPDATE_MULTI_UPDATE: bson_string_append (str, "MULTI"); break; case MONGOC_UPDATE_NONE: default: assert (false); } } } } return bson_string_free (str, false); /* detach buffer */ } static void request_from_update (request_t *request, const mongoc_rpc_t *rpc) { int32_t len; bson_t *doc; bson_string_t *update_as_str = bson_string_new ("OP_UPDATE "); char *str; memcpy (&len, rpc->update.selector, 4); len = BSON_UINT32_FROM_LE (len); doc = bson_new_from_data (rpc->update.selector, (size_t) len); assert (doc); _mongoc_array_append_val (&request->docs, doc); str = bson_as_json (doc, NULL); bson_string_append (update_as_str, str); bson_free (str); bson_string_append (update_as_str, ", "); memcpy (&len, rpc->update.update, 4); len = BSON_UINT32_FROM_LE (len); doc = bson_new_from_data (rpc->update.update, (size_t) len); assert (doc); _mongoc_array_append_val (&request->docs, doc); str = bson_as_json (doc, NULL); bson_string_append (update_as_str, str); bson_free (str); bson_string_append (update_as_str, " flags="); str = update_flags_str (rpc->update.flags); bson_string_append (update_as_str, str); bson_free (str); request->as_str = bson_string_free (update_as_str, false); } static char * delete_flags_str (uint32_t flags) { if (flags == MONGOC_DELETE_NONE) { return bson_strdup ("0"); } else { return bson_strdup ("SINGLE_REMOVE"); } } static void request_from_delete (request_t *request, const mongoc_rpc_t *rpc) { int32_t len; bson_t *doc; bson_string_t *delete_as_str = bson_string_new ("OP_DELETE "); char *str; memcpy (&len, rpc->delete_.selector, 4); len = BSON_UINT32_FROM_LE (len); doc = bson_new_from_data (rpc->delete_.selector, (size_t) len); assert (doc); _mongoc_array_append_val (&request->docs, doc); str = bson_as_json (doc, NULL); bson_string_append (delete_as_str, str); bson_free (str); bson_string_append (delete_as_str, " flags="); str = delete_flags_str (rpc->delete_.flags); bson_string_append (delete_as_str, str); bson_free (str); request->as_str = bson_string_free (delete_as_str, false); } static void request_from_killcursors (request_t *request, const mongoc_rpc_t *rpc) { /* protocol allows multiple cursor ids but we only implement one */ assert (rpc->kill_cursors.n_cursors == 1); request->as_str = bson_strdup_printf ("OP_KILLCURSORS %" PRId64, rpc->kill_cursors.cursors[0]); } static void request_from_getmore (request_t *request, const mongoc_rpc_t *rpc) { request->as_str = bson_strdup_printf ("getmore %s %" PRId64 " n_return=%d", rpc->get_more.collection, rpc->get_more.cursor_id, rpc->get_more.n_return); } libmongoc-1.3.1/tests/mock_server/request.h000066400000000000000000000065511264720626300210260ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef REQUEST_H #define REQUEST_H #include #include #include "mongoc.h" #include "mongoc-rpc-private.h" struct _mock_server_t; /* forward declaration */ typedef struct _request_t { uint8_t *data; size_t data_len; mongoc_rpc_t request_rpc; mongoc_opcode_t opcode; /* copied from rpc for convenience */ struct _mock_server_t *server; mongoc_stream_t *client; uint16_t client_port; bool is_command; char *command_name; char *as_str; mongoc_array_t docs; /* array of bson_t pointers */ } request_t; request_t *request_new (const mongoc_buffer_t *buffer, int32_t msg_len, struct _mock_server_t *server, mongoc_stream_t *client, uint16_t client_port); const bson_t * request_get_doc (const request_t *request, int n); bool request_matches_flags (const request_t *request, mongoc_query_flags_t flags); bool request_matches_query (const request_t *request, const char *ns, mongoc_query_flags_t flags, uint32_t skip, uint32_t n_return, const char *query_json, const char *fields_json, bool is_command); bool request_matches_insert (const request_t *request, const char *ns, mongoc_insert_flags_t flags, const char *doc_json); bool request_matches_bulk_insert (const request_t *request, const char *ns, mongoc_insert_flags_t flags, int n); bool request_matches_update (const request_t *request, const char *ns, mongoc_update_flags_t flags, const char *selector_json, const char *update_json); bool request_matches_delete (const request_t *request, const char *ns, mongoc_remove_flags_t flags, const char *selector_json); bool request_matches_getmore (const request_t *request, const char *ns, uint32_t n_return, int64_t cursor_id); bool request_matches_kill_cursors (const request_t *request, int64_t cursor_id); uint16_t request_get_server_port (request_t *request); uint16_t request_get_client_port (request_t *request); void request_destroy (request_t *request); #endif //REQUEST_H libmongoc-1.3.1/tests/mock_server/sync-queue.c000066400000000000000000000047151264720626300214270ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongoc-array-private.h" #include "mongoc-thread-private.h" #include "sync-queue.h" struct _sync_queue_t { mongoc_array_t array; mongoc_cond_t cond; mongoc_mutex_t mutex; }; sync_queue_t * q_new () { sync_queue_t *q = (sync_queue_t *)bson_malloc (sizeof(sync_queue_t)); _mongoc_array_init (&q->array, sizeof(void *)); mongoc_cond_init (&q->cond); mongoc_mutex_init (&q->mutex); return q; } void q_put (sync_queue_t *q, void *item) { mongoc_mutex_lock (&q->mutex); _mongoc_array_append_val (&q->array, item); mongoc_cond_signal (&q->cond); mongoc_mutex_unlock (&q->mutex); } /* call holding the lock */ static void * _get (sync_queue_t *q) { void **data; void *item = NULL; size_t i; if (q->array.len) { data = (void **)q->array.data; item = data[0]; /* shift the queue left */ q->array.len--; for (i = 0; i < q->array.len; i++) { data[i] = data[i + 1]; } } return item; } void * q_get (sync_queue_t *q, int64_t timeout_msec) { void *item = NULL; int64_t deadline; mongoc_mutex_lock (&q->mutex); if (timeout_msec) { deadline = bson_get_monotonic_time () + timeout_msec * 1000; while (!q->array.len && bson_get_monotonic_time () <= deadline) { mongoc_cond_timedwait (&q->cond, &q->mutex, timeout_msec); } } else { /* no deadline */ while (!q->array.len) { mongoc_cond_wait (&q->cond, &q->mutex); } } item = _get (q); mongoc_mutex_unlock (&q->mutex); return item; } void * q_get_nowait (sync_queue_t *q) { void *item; mongoc_mutex_lock (&q->mutex); item = _get (q); mongoc_mutex_unlock (&q->mutex); return item; } void q_destroy (sync_queue_t *q) { _mongoc_array_destroy (&q->array); mongoc_cond_destroy (&q->cond); mongoc_mutex_destroy (&q->mutex); bson_free (q); } libmongoc-1.3.1/tests/mock_server/sync-queue.h000066400000000000000000000016331264720626300214300ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #ifndef SYNC_QUEUE_H #define SYNC_QUEUE_H typedef struct _sync_queue_t sync_queue_t; sync_queue_t *q_new (); void q_put (sync_queue_t *q, void *item); void *q_get (sync_queue_t *q, int64_t timeout_msec); void *q_get_nowait (sync_queue_t *q); void q_destroy (sync_queue_t *q); #endif //SYNC_QUEUE_H libmongoc-1.3.1/tests/mongoc-tests.c000066400000000000000000000012561264720626300174310ustar00rootroot00000000000000#include "mongoc-tests.h" char *TEST_RESULT; void run_test (const char *name, void (*func) (void)) { struct timeval begin; struct timeval end; struct timeval diff; double format; TEST_RESULT = "PASS"; fprintf(stdout, "%-42s : ", name); fflush(stdout); bson_gettimeofday(&begin); func(); bson_gettimeofday(&end); fprintf(stdout, "%s", TEST_RESULT); diff.tv_sec = end.tv_sec - begin.tv_sec; diff.tv_usec = end.tv_usec - begin.tv_usec; if (diff.tv_usec < 0) { diff.tv_sec -= 1; diff.tv_usec = diff.tv_usec + 1000000; } format = diff.tv_sec + (diff.tv_usec / 1000000.0); fprintf(stdout, " : %lf\n", format); } libmongoc-1.3.1/tests/mongoc-tests.h000066400000000000000000000056031264720626300174360ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MONGOC_TESTS_H #define MONGOC_TESTS_H #ifdef BSON_DISABLE_ASSERT # undef BSON_DISABLE_ASSERT #endif #ifdef BSON_DISABLE_CHECKS # undef BSON_DISABLE_CHECKS #endif #include #include #include #include #ifdef _WIN32 # include #endif BSON_BEGIN_DECLS #ifdef _WIN32 # define gettestpid _getpid #else # define gettestpid getpid #endif #define assert_cmpstr(a, b) \ do { \ if (((a) != (b)) && !!strcmp((a), (b))) { \ fprintf(stderr, "FAIL\n\nAssert Failure: \"%s\" != \"%s\"\n", \ a, b); \ abort(); \ } \ } while (0) #define assert_cmpint(a, eq, b) \ do { \ if (!((a) eq (b))) { \ fprintf(stderr, "FAIL\n\nAssert Failure: %d %s %d\n" \ "%s:%d %s()\n", \ a, #eq, b, \ __FILE__, __LINE__, BSON_FUNC); \ abort(); \ } \ } while (0) #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) # define BEGIN_IGNORE_DEPRECATIONS \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") # define END_IGNORE_DEPRECATIONS \ _Pragma ("GCC diagnostic pop") #elif defined(__clang__) # define BEGIN_IGNORE_DEPRECATIONS \ _Pragma ("clang diagnostic push") \ _Pragma ("clang diagnostic ignored \"-Wdeprecated-declarations\"") # define END_IGNORE_DEPRECATIONS \ _Pragma ("clang diagnostic pop") #else # define BEGIN_IGNORE_DEPRECATIONS # define END_IGNORE_DEPRECATIONS #endif extern char *TEST_RESULT; void run_test (const char *name, void (*func) (void)); BSON_END_DECLS #endif /* MONGOC_TESTS_H */ libmongoc-1.3.1/tests/ssl-test.c000066400000000000000000000173711264720626300165720ustar00rootroot00000000000000#include #include #include #include #include "ssl-test.h" #define TIMEOUT 1000 #define NUM_IOVECS 2000 #define LOCALHOST "127.0.0.1" /** this function is meant to be run from ssl_test as a child thread * * It: * 1. spins up * 2. binds and listens to a random port * 3. notifies the client of its port through a condvar * 4. accepts a request * 5. reads a 32 bit length * 6. reads a string of that length * 7. echoes it back to the client * 8. shuts down */ static void * ssl_test_server (void * ptr) { ssl_test_data_t *data = (ssl_test_data_t *)ptr; mongoc_stream_t *sock_stream; mongoc_stream_t *ssl_stream; mongoc_socket_t *listen_sock; mongoc_socket_t *conn_sock; socklen_t sock_len; char buf[4 * NUM_IOVECS]; ssize_t r; mongoc_iovec_t iov; struct sockaddr_in server_addr = { 0 }; int len; iov.iov_base = buf; iov.iov_len = sizeof buf; listen_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (listen_sock); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); server_addr.sin_port = htons (0); r = mongoc_socket_bind (listen_sock, (struct sockaddr *)&server_addr, sizeof server_addr); assert (r == 0); sock_len = sizeof(server_addr); r = mongoc_socket_getsockname (listen_sock, (struct sockaddr *)&server_addr, &sock_len); assert(r == 0); r = mongoc_socket_listen (listen_sock, 10); assert(r == 0); mongoc_mutex_lock(&data->cond_mutex); data->server_port = ntohs(server_addr.sin_port); mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); conn_sock = mongoc_socket_accept (listen_sock, -1); assert (conn_sock); sock_stream = mongoc_stream_socket_new (conn_sock); assert (sock_stream); ssl_stream = mongoc_stream_tls_new(sock_stream, data->server, 0); if (!ssl_stream) { unsigned long err = ERR_get_error(); assert(err); data->server_result->ssl_err = err; data->server_result->result = SSL_TEST_SSL_INIT; mongoc_stream_destroy (sock_stream); mongoc_socket_destroy (listen_sock); return NULL; } assert(ssl_stream); r = mongoc_stream_tls_do_handshake (ssl_stream, TIMEOUT); if (!r) { unsigned long err = ERR_get_error(); assert(err); data->server_result->ssl_err = err; data->server_result->result = SSL_TEST_SSL_HANDSHAKE; mongoc_socket_destroy (listen_sock); mongoc_stream_destroy(ssl_stream); return NULL; } r = mongoc_stream_readv(ssl_stream, &iov, 1, 4, TIMEOUT); if (r < 0) { data->server_result->err = errno; data->server_result->result = SSL_TEST_TIMEOUT; mongoc_stream_destroy(ssl_stream); mongoc_socket_destroy (listen_sock); return NULL; } assert(r == 4); memcpy(&len, iov.iov_base, r); r = mongoc_stream_readv(ssl_stream, &iov, 1, len, TIMEOUT); assert(r == len); iov.iov_len = r; mongoc_stream_writev(ssl_stream, &iov, 1, TIMEOUT); mongoc_stream_destroy(ssl_stream); mongoc_socket_destroy (listen_sock); data->server_result->result = SSL_TEST_SUCCESS; return NULL; } /** this function is meant to be run from ssl_test as a child thread * * It: * 1. spins up * 2. waits on a condvar until the server is up * 3. connects to the server's port * 4. writes a 4 bytes length * 5. writes a string of length size * 6. reads a response back of the given length * 7. confirms that its the same as what was written * 8. shuts down */ static void * ssl_test_client (void * ptr) { ssl_test_data_t *data = (ssl_test_data_t *)ptr; mongoc_stream_t *sock_stream; mongoc_stream_t *ssl_stream; mongoc_socket_t *conn_sock; int i; int errno_captured; char buf[1024]; ssize_t r; mongoc_iovec_t riov; mongoc_iovec_t wiov; mongoc_iovec_t wiov_many[NUM_IOVECS]; struct sockaddr_in server_addr = { 0 }; int len; riov.iov_base = buf; riov.iov_len = sizeof buf; conn_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (conn_sock); mongoc_mutex_lock(&data->cond_mutex); while (! data->server_port) { mongoc_cond_wait(&data->cond, &data->cond_mutex); } mongoc_mutex_unlock(&data->cond_mutex); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(data->server_port); server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); r = mongoc_socket_connect (conn_sock, (struct sockaddr *)&server_addr, sizeof(server_addr), -1); if (r != 0) { fprintf (stderr, "mongoc_socket_connect returned %zd: \"%s\"", r, strerror (errno)); abort (); } sock_stream = mongoc_stream_socket_new (conn_sock); assert(sock_stream); ssl_stream = mongoc_stream_tls_new(sock_stream, data->client, 1); if (! ssl_stream) { unsigned long err = ERR_get_error(); assert(err); data->client_result->ssl_err = err; data->client_result->result = SSL_TEST_SSL_INIT; mongoc_stream_destroy(sock_stream); return NULL; } assert(ssl_stream); errno = 0; r = mongoc_stream_tls_do_handshake (ssl_stream, TIMEOUT); errno_captured = errno; if (! r) { unsigned long err = ERR_get_error(); assert(err || errno_captured); if (err) { data->client_result->ssl_err = err; } else { data->client_result->err = errno_captured; } data->client_result->result = SSL_TEST_SSL_HANDSHAKE; mongoc_stream_destroy(ssl_stream); return NULL; } r = mongoc_stream_tls_check_cert (ssl_stream, data->host); if (! r) { data->client_result->result = SSL_TEST_SSL_VERIFY; mongoc_stream_destroy(ssl_stream); return NULL; } len = 4 * NUM_IOVECS; wiov.iov_base = (void *)&len; wiov.iov_len = 4; r = mongoc_stream_writev(ssl_stream, &wiov, 1, TIMEOUT); assert(r == wiov.iov_len); for (i = 0; i < NUM_IOVECS; i++) { wiov_many[i].iov_base = (void *)"foo"; wiov_many[i].iov_len = 4; } r = mongoc_stream_writev(ssl_stream, wiov_many, NUM_IOVECS, TIMEOUT); assert(r == wiov_many[0].iov_len * NUM_IOVECS); riov.iov_len = 1; r = mongoc_stream_readv(ssl_stream, &riov, 1, 1, TIMEOUT); assert(r == 1); assert(memcmp(riov.iov_base, "f", 1) == 0); riov.iov_len = 3; r = mongoc_stream_readv(ssl_stream, &riov, 1, 3, TIMEOUT); assert(r == 3); assert(memcmp(riov.iov_base, "oo", 3) == 0); mongoc_stream_destroy(ssl_stream); data->client_result->result = SSL_TEST_SUCCESS; return NULL; } /** This is the testing function for the ssl-test lib * * The basic idea is that you spin up a client and server, which will * communicate over a mongoc-stream-tls, with varying mongoc_ssl_opt's. The * client and server speak a simple echo protocol, so all we're really testing * here is that any given configuration succeeds or fails as it should */ void ssl_test (mongoc_ssl_opt_t *client, mongoc_ssl_opt_t *server, const char *host, ssl_test_result_t *client_result, ssl_test_result_t *server_result) { ssl_test_data_t data = { 0 }; mongoc_thread_t threads[2]; int i, r; data.server = server; data.client = client; data.client_result = client_result; data.server_result = server_result; data.host = host; mongoc_mutex_init(&data.cond_mutex); mongoc_cond_init(&data.cond); r = mongoc_thread_create(threads, &ssl_test_server, &data); assert(r == 0); r = mongoc_thread_create(threads + 1, &ssl_test_client, &data); assert(r == 0); for (i = 0; i < 2; i++) { r = mongoc_thread_join(threads[i]); assert(r == 0); } mongoc_mutex_destroy(&data.cond_mutex); mongoc_cond_destroy(&data.cond); } libmongoc-1.3.1/tests/ssl-test.h000066400000000000000000000021721264720626300165700ustar00rootroot00000000000000#include #include typedef enum ssl_test_behavior { SSL_TEST_BEHAVIOR_NORMAL, SSL_TEST_BEHAVIOR_HANGUP_AFTER_HANDSHAKE, SSL_TEST_BEHAVIOR_STALL_BEFORE_HANDSHAKE, } ssl_test_behavior_t; typedef enum ssl_test_state { SSL_TEST_CRASH, SSL_TEST_SUCCESS, SSL_TEST_SSL_INIT, SSL_TEST_SSL_HANDSHAKE, SSL_TEST_SSL_VERIFY, SSL_TEST_TIMEOUT, } ssl_test_state_t; typedef struct ssl_test_result { ssl_test_state_t result; int err; unsigned long ssl_err; } ssl_test_result_t; typedef struct ssl_test_data { mongoc_ssl_opt_t *client; mongoc_ssl_opt_t *server; ssl_test_behavior_t behavior; int64_t handshake_stall_ms; const char *host; unsigned short server_port; mongoc_cond_t cond; mongoc_mutex_t cond_mutex; ssl_test_result_t *client_result; ssl_test_result_t *server_result; } ssl_test_data_t; void ssl_test (mongoc_ssl_opt_t *client, mongoc_ssl_opt_t *server, const char *host, ssl_test_result_t *client_result, ssl_test_result_t *server_result); libmongoc-1.3.1/tests/test-bulk.c000066400000000000000000002570631264720626300167320ustar00rootroot00000000000000#include #include #include #include "TestSuite.h" #include "test-libmongoc.h" #include "mongoc-tests.h" #include "mock_server/future-functions.h" #include "mock_server/mock-server.h" #include "test-conveniences.h" #include "mock_server/mock-rs.h" static char *gHugeString; static size_t gHugeStringLength; static char *gFourMBString; static size_t gFourMB = 1024 * 1024 * 4; void test_bulk_cleanup () { bson_free (gHugeString); } void init_huge_string (mongoc_client_t *client) { int32_t max_bson_size; assert (client); if (!gHugeString) { max_bson_size = mongoc_cluster_get_max_bson_obj_size(&client->cluster); assert (max_bson_size > 0); gHugeStringLength = (size_t) max_bson_size - 37; gHugeString = (char *)bson_malloc (gHugeStringLength); assert (gHugeString); memset (gHugeString, 'a', gHugeStringLength - 1); gHugeString[gHugeStringLength - 1] = '\0'; } } const char * huge_string (mongoc_client_t *client) { init_huge_string (client); return gHugeString; } size_t huge_string_length (mongoc_client_t *client) { init_huge_string (client); return gHugeStringLength; } void init_four_mb_string () { if (!gFourMBString) { gFourMBString = (char *)bson_malloc (gFourMB); assert (gFourMBString); memset (gFourMBString, 'a', gFourMB - 1); gFourMBString[gFourMB - 1] = '\0'; } } const char * four_mb_string () { init_four_mb_string (); return gFourMBString; } /*-------------------------------------------------------------------------- * * server_has_write_commands -- * * Decide with wire version if server supports write commands * * Returns: * True or false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool server_has_write_commands (mongoc_client_t *client) { bson_t *ismaster_cmd = tmp_bson ("{'ismaster': 1}"); bson_t ismaster; bson_iter_t iter; bool expect; assert (mongoc_client_command_simple (client, "admin", ismaster_cmd, NULL, &ismaster, NULL)); expect = (bson_iter_init_find_case (&iter, &ismaster, "maxWireVersion") && BSON_ITER_HOLDS_INT32 (&iter) && bson_iter_int32 (&iter) > 1); bson_destroy (&ismaster); return expect; } /*-------------------------------------------------------------------------- * * check_n_modified -- * * Check a bulk operation reply's nModified field is correct or absent. * * It may be omitted if we talked to a (<= 2.4.x) node, or a mongos * talked to a (<= 2.4.x) node. * * Returns: * None. * * Side effects: * Aborts if the field is incorrect. * *-------------------------------------------------------------------------- */ void check_n_modified (bool has_write_commands, const bson_t *reply, int32_t n_modified) { bson_iter_t iter; if (bson_iter_init_find (&iter, reply, "nModified")) { assert (has_write_commands); assert (BSON_ITER_HOLDS_INT32 (&iter)); assert (bson_iter_int32 (&iter) == n_modified); } else { assert (!has_write_commands); } } /*-------------------------------------------------------------------------- * * assert_error_count -- * * Check the length of a bulk operation reply's writeErrors. * * Returns: * None. * * Side effects: * Aborts if the array is the wrong length. * *-------------------------------------------------------------------------- */ void assert_error_count (int len, const bson_t *reply) { bson_iter_t iter; bson_iter_t error_iter; int n = 0; assert (bson_iter_init_find (&iter, reply, "writeErrors")); assert (bson_iter_recurse (&iter, &error_iter)); while (bson_iter_next (&error_iter)) { n++; } ASSERT_CMPINT (len, ==, n); } /*-------------------------------------------------------------------------- * * assert_n_inserted -- * * Check a bulk operation reply's nInserted field. * * Returns: * None. * * Side effects: * Aborts if the field is incorrect. * *-------------------------------------------------------------------------- */ void assert_n_inserted (int n, const bson_t *reply) { bson_iter_t iter; assert (bson_iter_init_find (&iter, reply, "nInserted")); assert (BSON_ITER_HOLDS_INT32 (&iter)); ASSERT_CMPINT (n, ==, bson_iter_int32 (&iter)); } /*-------------------------------------------------------------------------- * * assert_n_removed -- * * Check a bulk operation reply's nRemoved field. * * Returns: * None. * * Side effects: * Aborts if the field is incorrect. * *-------------------------------------------------------------------------- */ void assert_n_removed (int n, const bson_t *reply) { bson_iter_t iter; assert (bson_iter_init_find (&iter, reply, "nRemoved")); assert (BSON_ITER_HOLDS_INT32 (&iter)); ASSERT_CMPINT (n, ==, bson_iter_int32 (&iter)); } #define ASSERT_COUNT(n, collection) \ do { \ int count = (int)mongoc_collection_count (collection, MONGOC_QUERY_NONE, \ NULL, 0, 0, NULL, NULL); \ if ((n) != count) { \ fprintf(stderr, "FAIL\n\nAssert Failure: count of %s is %d, not %d\n" \ "%s:%d %s()\n", \ mongoc_collection_get_name (collection), count, n, \ __FILE__, __LINE__, BSON_FUNC); \ abort(); \ } \ } while (0) /*-------------------------------------------------------------------------- * * oid_created_on_client -- * * Check that a document's _id contains this process's pid. * * Returns: * True or false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool oid_created_on_client (const bson_t *doc) { bson_oid_t new_oid; const uint8_t *new_pid; bson_iter_t iter; const bson_oid_t *oid; const uint8_t *pid; bson_oid_init (&new_oid, NULL); new_pid = &new_oid.bytes[7]; bson_iter_init_find (&iter, doc, "_id"); if (!BSON_ITER_HOLDS_OID (&iter)) { return false; } oid = bson_iter_oid (&iter); pid = &oid->bytes[7]; return 0 == memcmp (pid, new_pid, 2); } static mongoc_collection_t * get_test_collection (mongoc_client_t *client, const char *prefix) { mongoc_collection_t *ret; char *str; str = gen_collection_name (prefix); ret = mongoc_client_get_collection (client, "test", str); bson_free (str); return ret; } void create_unique_index (mongoc_collection_t *collection) { mongoc_index_opt_t opt; bson_error_t error; mongoc_index_opt_init (&opt); opt.unique = true; ASSERT_OR_PRINT (mongoc_collection_create_index ( collection, tmp_bson ("{'a': 1}"), &opt, &error), error); } static void test_bulk (void) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bool has_write_cmds; bson_error_t error; bson_t reply; bson_t child; bson_t del; bson_t up; bson_t doc = BSON_INITIALIZER; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_bulk"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); assert (bulk); mongoc_bulk_operation_insert (bulk, &doc); mongoc_bulk_operation_insert (bulk, &doc); mongoc_bulk_operation_insert (bulk, &doc); mongoc_bulk_operation_insert (bulk, &doc); bson_init (&up); bson_append_document_begin (&up, "$set", -1, &child); bson_append_int32 (&child, "hello", -1, 123); bson_append_document_end (&up, &child); mongoc_bulk_operation_update (bulk, &doc, &up, false); bson_destroy (&up); bson_init (&del); BSON_APPEND_INT32 (&del, "hello", 123); mongoc_bulk_operation_remove (bulk, &del); bson_destroy (&del); ASSERT_OR_PRINT (mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 4," " 'nMatched': 4," " 'nRemoved': 4," " 'nUpserted': 0}"); check_n_modified (has_write_cmds, &reply, 4); ASSERT_COUNT (0, collection); bson_destroy (&reply); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_insert (bool ordered) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bool has_write_cmds; bson_error_t error; bson_t reply; bson_t doc = BSON_INITIALIZER; bson_t query = BSON_INITIALIZER; mongoc_cursor_t *cursor; const bson_t *inserted_doc; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_insert"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); assert (bulk); assert (bulk->flags.ordered == ordered); mongoc_bulk_operation_insert (bulk, &doc); mongoc_bulk_operation_insert (bulk, &doc); ASSERT_OR_PRINT (mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 2," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0}"); check_n_modified (has_write_cmds, &reply, 0); bson_destroy (&reply); ASSERT_COUNT (2, collection); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, NULL); assert (cursor); while (mongoc_cursor_next (cursor, &inserted_doc)) { assert (oid_created_on_client (inserted_doc)); } ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_cursor_destroy (cursor); bson_destroy (&query); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&doc); } static void test_insert_ordered (void) { test_insert (true); } static void test_insert_unordered (void) { test_insert (false); } static void test_insert_check_keys (void) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bool has_write_cmds; bson_t *doc; bson_t reply; bson_error_t error; bool r; char *json_pattern; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_insert_check_keys"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); assert (bulk); doc = tmp_bson ("{'$dollar': 1}"); mongoc_bulk_operation_insert (bulk, doc); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_COMMAND); assert (error.code); json_pattern = bson_strdup_printf ("{'nInserted': 0," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [" " {'index': 0, 'code': %d}" " ]}", error.code); ASSERT_MATCH (&reply, json_pattern); check_n_modified (has_write_cmds, &reply, 0); assert_error_count (1, &reply); ASSERT_COUNT (0, collection); bson_free (json_pattern); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_upsert (bool ordered) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bool has_write_cmds; bson_error_t error; bson_t reply; bson_t *sel; bson_t *doc; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_upsert"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); assert (bulk); sel = tmp_bson ("{'_id': 1234}"); doc = tmp_bson ("{'$set': {'hello': 'there'}}"); mongoc_bulk_operation_update (bulk, sel, doc, true); ASSERT_OR_PRINT (mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 1," " 'upserted': [{'index': 0, '_id': 1234}]," " 'writeErrors': []}"); check_n_modified (has_write_cmds, &reply, 0); ASSERT_COUNT (1, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); assert (bulk); /* non-upsert, no matches */ sel = tmp_bson ("{'_id': 2}"); doc = tmp_bson ("{'$set': {'hello': 'there'}}"); mongoc_bulk_operation_update (bulk, sel, doc, false); ASSERT_OR_PRINT (mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'upserted': {'$exists': false}," " 'writeErrors': []}"); check_n_modified (has_write_cmds, &reply, 0); ASSERT_COUNT (1, collection); /* doc remains from previous operation */ ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_upsert_ordered (void) { test_upsert (true); } static void test_upsert_unordered (void) { test_upsert (false); } static void test_upserted_index (bool ordered) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bool has_write_cmds; bson_error_t error; bson_t reply; bson_t *emp = tmp_bson ("{}"); bson_t *inc = tmp_bson ("{'$inc': {'b': 1}}"); bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_upserted_index"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); assert (bulk); mongoc_bulk_operation_insert (bulk, emp); mongoc_bulk_operation_insert (bulk, emp); mongoc_bulk_operation_remove (bulk, tmp_bson ("{'i': 2}")); mongoc_bulk_operation_update (bulk, tmp_bson ("{'i': 3}"), inc, false); /* upsert */ mongoc_bulk_operation_update (bulk, tmp_bson ("{'i': 4}"), inc, true); mongoc_bulk_operation_remove (bulk, tmp_bson ("{'i': 5}")); mongoc_bulk_operation_remove_one (bulk, tmp_bson ("{'i': 6}")); mongoc_bulk_operation_replace_one (bulk, tmp_bson ("{'i': 7}"), emp, false); /* upsert */ mongoc_bulk_operation_replace_one (bulk, tmp_bson ("{'i': 8}"), emp, true); /* upsert */ mongoc_bulk_operation_replace_one (bulk, tmp_bson ("{'i': 9}"), emp, true); mongoc_bulk_operation_remove (bulk, tmp_bson ("{'i': 10}")); mongoc_bulk_operation_insert (bulk, emp); mongoc_bulk_operation_insert (bulk, emp); mongoc_bulk_operation_update (bulk, tmp_bson ("{'i': 13}"), inc, false); /* upsert */ mongoc_bulk_operation_update (bulk, tmp_bson ("{'i': 14}"), inc, true); mongoc_bulk_operation_insert (bulk, emp); /* upserts */ mongoc_bulk_operation_update (bulk, tmp_bson ("{'i': 16}"), inc, true); mongoc_bulk_operation_update (bulk, tmp_bson ("{'i': 17}"), inc, true); /* non-upsert */ mongoc_bulk_operation_update (bulk, tmp_bson ("{'i': 18}"), inc, false); /* upserts */ mongoc_bulk_operation_update (bulk, tmp_bson ("{'i': 19}"), inc, true); mongoc_bulk_operation_replace_one (bulk, tmp_bson ("{'i': 20}"), emp, true); mongoc_bulk_operation_replace_one (bulk, tmp_bson ("{'i': 21}"), emp, true); mongoc_bulk_operation_replace_one (bulk, tmp_bson ("{'i': 22}"), emp, true); mongoc_bulk_operation_update (bulk, tmp_bson ("{'i': 23}"), inc, true); /* non-upsert */ mongoc_bulk_operation_update_one (bulk, tmp_bson ("{'i': 24}"), inc, false); /* upsert */ mongoc_bulk_operation_update_one (bulk, tmp_bson ("{'i': 25}"), inc, true); /* non-upserts */ mongoc_bulk_operation_remove (bulk, tmp_bson ("{'i': 26}")); mongoc_bulk_operation_remove (bulk, tmp_bson ("{'i': 27}")); mongoc_bulk_operation_update_one (bulk, tmp_bson ("{'i': 28}"), inc, false); mongoc_bulk_operation_update_one (bulk, tmp_bson ("{'i': 29}"), inc, false); /* each update modifies existing 16 docs, but only increments index by one */ mongoc_bulk_operation_update (bulk, emp, inc, false); mongoc_bulk_operation_update (bulk, emp, inc, false); /* upsert */ mongoc_bulk_operation_update_one (bulk, tmp_bson ("{'i': 32}"), inc, true); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); if (!r) { fprintf (stderr, "bulk failed: %s\n", error.message); abort (); } ASSERT_MATCH (&reply, "{'nInserted': 5," " 'nMatched': 34," " 'nRemoved': 0," " 'nUpserted': 13," " 'upserted': [" " {'index': 4}," " {'index': 8}," " {'index': 9}," " {'index': 14}," " {'index': 16}," " {'index': 17}," " {'index': 19}," " {'index': 20}," " {'index': 21}," " {'index': 22}," " {'index': 23}," " {'index': 25}," " {'index': 32}" " ]," " 'writeErrors': []}"); check_n_modified (has_write_cmds, &reply, 34); ASSERT_COUNT (18, collection); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_upserted_index_ordered (void) { test_upserted_index (true); } static void test_upserted_index_unordered (void) { test_upserted_index (false); } static void test_update_one (bool ordered) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bool has_write_cmds; bson_error_t error; bson_t reply; bson_t *sel; bson_t *doc; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_update_one"); assert (collection); doc = bson_new (); r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, NULL); assert (r); r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, NULL); assert (r); bson_destroy (doc); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); assert (bulk); sel = tmp_bson ("{}"); doc = tmp_bson ("{'$set': {'hello': 'there'}}"); mongoc_bulk_operation_update_one (bulk, sel, doc, true); ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 1," " 'nRemoved': 0," " 'nUpserted': 0," " 'upserted': {'$exists': false}," " 'writeErrors': []}"); check_n_modified (has_write_cmds, &reply, 1); ASSERT_COUNT (2, collection); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_update_one_ordered (void) { test_update_one (true); } static void test_update_one_unordered (void) { test_update_one (false); } static void test_replace_one (bool ordered) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bool has_write_cmds; bson_error_t error; bson_t reply; bson_t *sel; bson_t *doc; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_replace_one"); assert (collection); doc = bson_new (); r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, NULL); assert (r); r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, NULL); assert (r); bson_destroy (doc); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); assert (bulk); sel = tmp_bson ("{}"); doc = tmp_bson ("{'hello': 'there'}"); mongoc_bulk_operation_replace_one (bulk, sel, doc, true); ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 1," " 'nRemoved': 0," " 'nUpserted': 0," " 'upserted': {'$exists': false}," " 'writeErrors': []}"); check_n_modified (has_write_cmds, &reply, 1); ASSERT_COUNT (2, collection); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_upsert_large (void) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bool has_write_cmds; bson_t *sel = tmp_bson ("{'_id': 1}"); bson_t doc = BSON_INITIALIZER; bson_t child = BSON_INITIALIZER; bson_t query = BSON_INITIALIZER; const bson_t *retdoc; bson_error_t error; bson_t reply; mongoc_cursor_t *cursor; int ok = 0; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_upsert_large"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); assert (bulk); bson_append_document_begin (&doc, "$set", -1, &child); assert (bson_append_utf8 (&child, "x", -1, huge_string (client), (int) huge_string_length (client))); bson_append_document_end (&doc, &child); mongoc_bulk_operation_update (bulk, sel, &doc, true); ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 1," " 'upserted': [{'index': 0, '_id': 1}]," " 'writeErrors': []}"); check_n_modified (has_write_cmds, &reply, 0); ASSERT_COUNT (1, collection); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, NULL); while (mongoc_cursor_next (cursor, &retdoc)) { ok++; } ASSERT_CMPINT (ok, ==, 1); if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "ERROR: %s\n", error.message); ASSERT (false); } bson_destroy (&query); bson_destroy (&reply); bson_destroy (&doc); mongoc_cursor_destroy (cursor); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_replace_one_ordered (void) { test_replace_one (true); } static void test_replace_one_unordered (void) { test_replace_one (false); } static void test_update (bool ordered) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; bson_t *docs_inserted[] = { tmp_bson ("{'a': 1}"), tmp_bson ("{'a': 2}"), tmp_bson ("{'a': 3, 'foo': 'bar'}"), }; unsigned int i; mongoc_bulk_operation_t *bulk; bson_error_t error; bson_t reply; bson_t *sel; bson_t *bad_update_doc = tmp_bson ("{'foo': 'bar'}"); bson_t *update_doc; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_update"); assert (collection); for (i = 0; i < sizeof docs_inserted / sizeof (bson_t *); i++) { assert (mongoc_collection_insert (collection, MONGOC_INSERT_NONE, docs_inserted[i], NULL, NULL)); } bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); assert (bulk); /* update doc without $-operators rejected */ sel = tmp_bson ("{'a': {'$gte': 2}}"); suppress_one_message (); mongoc_bulk_operation_update (bulk, sel, bad_update_doc, false); ASSERT_CMPINT (0, ==, (int)bulk->commands.len); update_doc = tmp_bson ("{'$set': {'foo': 'bar'}}"); mongoc_bulk_operation_update (bulk, sel, update_doc, false); ASSERT_OR_PRINT (mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 2," " 'nRemoved': 0," " 'nUpserted': 0," " 'upserted': {'$exists': false}," " 'writeErrors': []}"); /* one doc already had "foo": "bar" */ check_n_modified (has_write_cmds, &reply, 1); ASSERT_COUNT (3, collection); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_bulk_operation_destroy (bulk); bson_destroy (&reply); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_update_ordered (void) { test_update (true); } static void test_update_unordered (void) { test_update (false); } static void test_index_offset (void) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bool has_write_cmds; bson_error_t error; bson_t reply; bson_t *sel; bson_t *doc; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_index_offset"); assert (collection); doc = tmp_bson ("{}"); BSON_APPEND_INT32 (doc, "_id", 1234); r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error); assert (r); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); assert (bulk); sel = tmp_bson ("{'_id': 1234}"); doc = tmp_bson ("{'$set': {'hello': 'there'}}"); mongoc_bulk_operation_remove_one (bulk, sel); mongoc_bulk_operation_update (bulk, sel, doc, true); ASSERT_OR_PRINT (mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 0," " 'nRemoved': 1," " 'nUpserted': 1," " 'upserted': [{'index': 1, '_id': 1234}]," " 'writeErrors': []}"); check_n_modified (has_write_cmds, &reply, 0); ASSERT_COUNT (1, collection); bson_destroy (&reply); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_single_ordered_bulk (void) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_single_ordered_bulk"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); assert (bulk); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'a': 1}")); mongoc_bulk_operation_update (bulk, tmp_bson ("{'a': 1}"), tmp_bson ("{'$set': {'b': 1}}"), false); mongoc_bulk_operation_update (bulk, tmp_bson ("{'a': 2}"), tmp_bson ("{'$set': {'b': 2}}"), true); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'a': 3}")); mongoc_bulk_operation_remove (bulk, tmp_bson ("{'a': 3}")); ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 2," " 'nMatched': 1," " 'nRemoved': 1," " 'nUpserted': 1," " 'upserted': [{'index': 2, '_id': {'$exists': true}}]" "}"); check_n_modified (has_write_cmds, &reply, 1); ASSERT_COUNT (2, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_insert_continue_on_error (void) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t *doc0 = tmp_bson ("{'a': 1}"); bson_t *doc1 = tmp_bson ("{'a': 2}"); bson_t reply; bson_error_t error; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_insert_continue_on_error"); assert (collection); create_unique_index (collection); bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); mongoc_bulk_operation_insert (bulk, doc0); mongoc_bulk_operation_insert (bulk, doc0); mongoc_bulk_operation_insert (bulk, doc1); mongoc_bulk_operation_insert (bulk, doc1); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); ASSERT_MATCH (&reply, "{'nInserted': 2," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [{'index': 1}, {'index': 3}]}"); check_n_modified (has_write_cmds, &reply, 0); assert_error_count (2, &reply); ASSERT_COUNT (2, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_update_continue_on_error (void) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t *doc0 = tmp_bson ("{'a': 1}"); bson_t *doc1 = tmp_bson ("{'a': 2}"); bson_t reply; bson_error_t error; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_update_continue_on_error"); assert (collection); create_unique_index (collection); mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc0, NULL, NULL); mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc1, NULL, NULL); bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); /* succeeds */ mongoc_bulk_operation_update (bulk, doc0, tmp_bson ("{'$inc': {'b': 1}}"), false); /* fails */ mongoc_bulk_operation_update (bulk, doc0, tmp_bson ("{'$set': {'a': 2}}"), false); /* succeeds */ mongoc_bulk_operation_update (bulk, doc1, tmp_bson ("{'$set': {'b': 2}}"), false); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 2," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [{'index': 1}]}"); check_n_modified (has_write_cmds, &reply, 2); assert_error_count (1, &reply); ASSERT_COUNT (2, collection); ASSERT_CMPINT ( 1, ==, (int)mongoc_collection_count (collection, MONGOC_QUERY_NONE, tmp_bson ("{'b': 2}"), 0, 0, NULL, NULL)); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_remove_continue_on_error (void) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t *doc0 = tmp_bson ("{'a': 1}"); bson_t *doc1 = tmp_bson ("{'a': 2}"); bson_t *doc2 = tmp_bson ("{'a': 3}"); bson_t reply; bson_error_t error; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_remove_continue_on_error"); assert (collection); mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc0, NULL, NULL); mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc1, NULL, NULL); mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc2, NULL, NULL); bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); /* succeeds */ mongoc_bulk_operation_remove_one (bulk, doc0); /* fails */ mongoc_bulk_operation_remove_one (bulk, tmp_bson ("{'a': {'$bad': 1}}")); /* succeeds */ mongoc_bulk_operation_remove_one (bulk, doc1); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 0," " 'nRemoved': 2," " 'nUpserted': 0," " 'writeErrors': [{'index': 1}]}"); check_n_modified (has_write_cmds, &reply, 0); assert_error_count (1, &reply); ASSERT_COUNT (1, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_single_error_ordered_bulk (void) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_single_error_ordered_bulk"); assert (collection); create_unique_index (collection); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); assert (bulk); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 1, 'a': 1}")); mongoc_bulk_operation_update (bulk, tmp_bson ("{'b': 2}"), tmp_bson ("{'$set': {'a': 1}}"), true); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 3, 'a': 2}")); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_COMMAND); /* TODO: CDRIVER-651, assert contents of the 'op' field */ ASSERT_MATCH (&reply, "{'nInserted': 1," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [" " {'index': 1," " 'code': {'$exists': true}," " 'errmsg': {'$exists': true}}]" /* * " 'writeErrors.0.op': ...," */ "}"); assert_error_count (1, &reply); check_n_modified (has_write_cmds, &reply, 0); ASSERT_COUNT (1, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_multiple_error_ordered_bulk (void) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_multiple_error_ordered_bulk"); assert (collection); create_unique_index (collection); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); assert (bulk); /* 0 succeeds */ mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 1, 'a': 1}")); /* 1 succeeds */ mongoc_bulk_operation_update (bulk, tmp_bson ("{'b': 3}"), tmp_bson ("{'$set': {'a': 2}}"), true); /* 2 fails, duplicate value for 'a' */ mongoc_bulk_operation_update (bulk, tmp_bson ("{'b': 2}"), tmp_bson ("{'$set': {'a': 1}}"), true); /* 3 not attempted, bulk is already aborted */ mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 4, 'a': 3}")); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_COMMAND); assert (error.code); /* TODO: CDRIVER-651, assert contents of the 'op' field */ ASSERT_MATCH (&reply, "{'nInserted': 1," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 1," " 'writeErrors': [" " {'index': 2, 'errmsg': {'$exists': true}}" "]" /* * " 'writeErrors.0.op': {'q': {'b': 2}, 'u': {'$set': {'a': 1}}, 'multi': false}" */ "}"); check_n_modified (has_write_cmds, &reply, 0); assert_error_count (1, &reply); ASSERT_COUNT (2, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_single_unordered_bulk (void) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_single_unordered_bulk"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'a': 1}")); mongoc_bulk_operation_update (bulk, tmp_bson ("{'a': 1}"), tmp_bson ("{'$set': {'b': 1}}"), false); mongoc_bulk_operation_update (bulk, tmp_bson ("{'a': 2}"), tmp_bson ("{'$set': {'b': 2}}"), true); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'a': 3}")); mongoc_bulk_operation_remove (bulk, tmp_bson ("{'a': 3}")); ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 2," " 'nMatched': 1," " 'nRemoved': 1," " 'nUpserted': 1," " 'upserted': [" " {'index': 2, '_id': {'$exists': true}}]," " 'writeErrors': []}"); check_n_modified (has_write_cmds, &reply, 1); ASSERT_COUNT (2, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_single_error_unordered_bulk (void) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_single_error_unordered_bulk"); assert (collection); create_unique_index (collection); bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); /* 0 succeeds */ mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 1, 'a': 1}")); /* 1 fails */ mongoc_bulk_operation_update (bulk, tmp_bson ("{'b': 2}"), tmp_bson ("{'$set': {'a': 1}}"), true); /* 2 succeeds */ mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 3, 'a': 2}")); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_COMMAND); assert (error.code); /* TODO: CDRIVER-651, assert contents of the 'op' field */ ASSERT_MATCH (&reply, "{'nInserted': 2," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [{'index': 1," " 'code': {'$exists': true}," " 'errmsg': {'$exists': true}}]}"); assert_error_count (1, &reply); check_n_modified (has_write_cmds, &reply, 0); ASSERT_COUNT (2, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void _test_write_concern (bool has_write_commands, bool ordered, bool multi_err) { mock_server_t *mock_server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_write_concern_t *wc; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; mongoc_insert_flags_t insert_flags; future_t *future; request_t *request; int32_t first_err; int32_t second_err; /* set wire protocol version for legacy writes or write commands */ mock_server = mock_server_with_autoismaster (has_write_commands ? 3 : 0); mock_server_run (mock_server); client = mongoc_client_new_from_uri (mock_server_get_uri (mock_server)); collection = mongoc_client_get_collection (client, "test", "test"); wc = mongoc_write_concern_new (); mongoc_write_concern_set_w (wc, 2); mongoc_write_concern_set_wtimeout (wc, 100); bulk = mongoc_collection_create_bulk_operation (collection, ordered, wc); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'_id': 1}")); mongoc_bulk_operation_remove (bulk, tmp_bson ("{'_id': 2}")); future = future_bulk_operation_execute (bulk, &reply, &error); if (has_write_commands) { request = mock_server_receives_command ( mock_server, "test", MONGOC_QUERY_NONE, "{'insert': 'test'," " 'writeConcern': {'w': 2, 'wtimeout': 100}," " 'ordered': %s," " 'documents': [{'_id': 1}]}", ordered ? "true" : "false"); assert (request); mock_server_replies_simple ( request, "{'ok': 1.0, 'n': 1, " " 'writeConcernError': {'code': 17, 'errmsg': 'foo'}}"); request_destroy (request); request = mock_server_receives_command ( mock_server, "test", MONGOC_QUERY_NONE, "{'delete': 'test'," " 'writeConcern': {'w': 2, 'wtimeout': 100}," " 'ordered': %s," " 'deletes': [{'q': {'_id': 2}, 'limit': 0}]}", ordered ? "true" : "false"); if (multi_err) { mock_server_replies_simple ( request, "{'ok': 1.0, 'n': 1, " " 'writeConcernError': {'code': 42, 'errmsg': 'bar'}}"); } else { mock_server_replies_simple (request, "{'ok': 1.0, 'n': 1}"); } request_destroy (request); /* server fictionally returns 17 and 42; expect driver to use first one */ first_err = 17; second_err = 42; } else { insert_flags = ordered ? MONGOC_INSERT_NONE : MONGOC_INSERT_CONTINUE_ON_ERROR; request = mock_server_receives_insert ( mock_server, "test.test", insert_flags, "{'_id': 1}"); request_destroy (request); request = mock_server_receives_command ( mock_server, "test", MONGOC_QUERY_NONE, "{'getLastError': 1, 'w': 2, 'wtimeout': 100}"); assert (request); mock_server_replies_simple ( request, "{'ok': 1.0, 'n': 1, 'err': 'foo', 'wtimeout': true}"); request_destroy (request); request = mock_server_receives_delete ( mock_server, "test.test", MONGOC_REMOVE_NONE, "{'_id': 2}"); request_destroy (request); request = mock_server_receives_command ( mock_server, "test", MONGOC_QUERY_NONE, "{'getLastError': 1, 'w': 2, 'wtimeout': 100}"); if (multi_err) { mock_server_replies_simple ( request, "{'ok': 1.0, 'n': 1, 'err': 'bar', 'wtimeout': true}"); } else { mock_server_replies_simple (request, "{'ok': 1.0, 'n': 1}"); } request_destroy (request); /* The client makes up the error code for legacy writes */ first_err = second_err = 64; } /* join thread, assert mongoc_bulk_operation_execute () returned 0 */ assert (!future_get_uint32_t (future)); if (multi_err) { ASSERT_MATCH (&reply, "{'nInserted': 1," " 'nMatched': 0," " 'nRemoved': 1," " 'nUpserted': 0," " 'writeErrors': []," " 'writeConcernErrors': [" " {'code': %d, 'errmsg': 'foo'}," " {'code': %d, 'errmsg': 'bar'}]}", first_err, second_err); ASSERT_CMPSTR ("Multiple write concern errors: \"foo\", \"bar\"", error.message); } else { ASSERT_MATCH (&reply, "{'nInserted': 1," " 'nMatched': 0," " 'nRemoved': 1," " 'nUpserted': 0," " 'writeErrors': []," " 'writeConcernErrors': [" " {'code': %d, 'errmsg': 'foo'}]}", first_err); ASSERT_CMPSTR ("foo", error.message); } check_n_modified (has_write_commands, &reply, 0); ASSERT_CMPINT (MONGOC_ERROR_WRITE_CONCERN, ==, error.domain); ASSERT_CMPINT (first_err, ==, error.code); future_destroy (future); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_write_concern_destroy (wc); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (mock_server); } static void test_write_concern_legacy_ordered (void) { _test_write_concern (false, true, false); } static void test_write_concern_legacy_ordered_multi_err (void) { _test_write_concern (false, true, true); } static void test_write_concern_legacy_unordered (void) { _test_write_concern (false, false, false); } static void test_write_concern_legacy_unordered_multi_err (void) { _test_write_concern (false, false, true); } static void test_write_concern_write_command_ordered (void) { _test_write_concern (true, true, false); } static void test_write_concern_write_command_ordered_multi_err (void) { _test_write_concern (true, true, true); } static void test_write_concern_write_command_unordered (void) { _test_write_concern (true, false, false); } static void test_write_concern_write_command_unordered_multi_err (void) { _test_write_concern (true, false, true); } static void test_multiple_error_unordered_bulk (void) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; bool r; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "test_multiple_error_unordered_bulk"); assert (collection); create_unique_index (collection); bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 1, 'a': 1}")); mongoc_bulk_operation_update (bulk, tmp_bson ("{'b': 2}"), tmp_bson ("{'$set': {'a': 3}}"), true); mongoc_bulk_operation_update (bulk, tmp_bson ("{'b': 3}"), tmp_bson ("{'$set': {'a': 4}}"), true); mongoc_bulk_operation_update (bulk, tmp_bson ("{'b': 4}"), tmp_bson ("{'$set': {'a': 3}}"), true); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 5, 'a': 2}")); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 6, 'a': 1}")); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_COMMAND); assert (error.code); /* Assume the update at index 1 runs before the update at index 3, * although the spec does not require it. Same for inserts. */ /* TODO: CDRIVER-651, assert contents of the 'op' field */ ASSERT_MATCH (&reply, "{'nInserted': 2," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 2," /* " 'writeErrors.0.op': {'q': {'b': 4}, 'u': {'$set': {'a': 3}}, 'multi': false, 'upsert': true}}," */ " 'writeErrors.0.index': 3," " 'writeErrors.0.code': {'$exists': true}," " 'writeErrors.1.index': 5," /* " 'writeErrors.1.op': {'_id': '...', 'b': 6, 'a': 1}," */ " 'writeErrors.1.code': {'$exists': true}," " 'writeErrors.1.errmsg': {'$exists': true}}"); assert_error_count (2, &reply); check_n_modified (has_write_cmds, &reply, 0); /* * assume the update at index 1 runs before the update at index 3, * although the spec does not require it. Same for inserts. */ ASSERT_COUNT (4, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void _test_wtimeout_plus_duplicate_key_err (bool has_write_commands) { mock_server_t *mock_server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; future_t *future; request_t *request; /* set wire protocol version for legacy writes or write commands */ mock_server = mock_server_with_autoismaster (has_write_commands ? 3 : 0); mock_server_run (mock_server); client = mongoc_client_new_from_uri (mock_server_get_uri (mock_server)); collection = mongoc_client_get_collection (client, "test", "test"); /* unordered bulk */ bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'_id': 1}")); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'_id': 2}")); mongoc_bulk_operation_remove (bulk, tmp_bson ("{'_id': 3}")); future = future_bulk_operation_execute (bulk, &reply, &error); if (has_write_commands) { request = mock_server_receives_command ( mock_server, "test", MONGOC_QUERY_NONE, "{'insert': 'test'," " 'writeConcern': {}," " 'ordered': false," " 'documents': [{'_id': 1}, {'_id': 2}]}"); assert (request); mock_server_replies ( request, 0, 0, 0, 1, "{'ok': 1.0, 'n': 1," " 'writeErrors': [{'index': 0, 'code': 11000, 'errmsg': 'dupe'}]," " 'writeConcernError': {'code': 17, 'errmsg': 'foo'}}"); request = mock_server_receives_command ( mock_server, "test", MONGOC_QUERY_NONE, "{'delete': 'test'," " 'writeConcern': {}," " 'ordered': false," " 'deletes': [{'q': {'_id': 3}, 'limit': 0}]}"); assert (request); mock_server_replies ( request, 0, 0, 0, 1, "{'ok': 1.0, 'n': 1," " 'writeConcernError': {'code': 42, 'errmsg': 'bar'}}"); request_destroy (request); } else { request = mock_server_receives_insert ( mock_server, "test.test", MONGOC_INSERT_CONTINUE_ON_ERROR, "{'_id': 1}"); request_destroy (request); request = mock_server_receives_gle (mock_server, "test"); mock_server_replies ( request, 0, 0, 0, 1, "{'ok': 1.0, 'n': 0, 'code': 11000, 'err': 'dupe'}"); request_destroy (request); request = mock_server_receives_insert ( mock_server, "test.test", MONGOC_INSERT_CONTINUE_ON_ERROR, "{'_id': 2}"); request_destroy (request); request = mock_server_receives_gle (mock_server, "test"); mock_server_replies ( request, 0, 0, 0, 1, "{'ok': 1.0, 'n': 1, 'err': 'foo', 'wtimeout': true}"); request_destroy (request); request = mock_server_receives_delete ( mock_server, "test.test", MONGOC_REMOVE_NONE, "{'_id': 3}"); request_destroy (request); request = mock_server_receives_gle (mock_server, "test"); mock_server_replies ( request, 0, 0, 0, 1, "{'ok': 1.0, 'n': 1, 'err': 'bar', 'wtimeout': true}"); request_destroy (request); } /* mongoc_bulk_operation_execute () returned 0 */ assert (!future_get_uint32_t (future)); /* get err code from server with write commands, otherwise use 64 */ ASSERT_MATCH (&reply, "{'nInserted': 1," " 'nMatched': 0," " 'nRemoved': 1," " 'nUpserted': 0," " 'writeErrors': [" " {'index': 0, 'code': 11000, 'errmsg': 'dupe'}]," " 'writeConcernErrors': [" " {'code': %d, 'errmsg': 'foo'}," " {'code': %d, 'errmsg': 'bar'}]}", has_write_commands ? 17 : 64, has_write_commands ? 42 : 64); check_n_modified (has_write_commands, &reply, 0); future_destroy (future); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (mock_server); } static void test_wtimeout_plus_duplicate_key_err_legacy (void) { _test_wtimeout_plus_duplicate_key_err (false); } static void test_wtimeout_plus_duplicate_key_err_write_commands (void) { _test_wtimeout_plus_duplicate_key_err (true); } static void test_large_inserts_ordered (void) { mongoc_client_t *client; bool has_write_cmds; bson_t *huge_doc; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; bool r; bson_t *big_doc; bson_iter_t iter; int i; const bson_t *retdoc; bson_t query = BSON_INITIALIZER; mongoc_cursor_t *cursor; int ok = 0; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); huge_doc = BCON_NEW ("a", BCON_INT32 (1)); bson_append_utf8 (huge_doc, "long-key-to-make-this-fail", -1, huge_string (client), (int) huge_string_length (client)); collection = get_test_collection (client, "test_large_inserts_ordered"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); assert (bulk); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 1, 'a': 1}")); mongoc_bulk_operation_insert (bulk, huge_doc); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 2, 'a': 2}")); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); /* TODO: CDRIVER-662, should always be MONGOC_ERROR_BSON */ if (!( (error.domain == MONGOC_ERROR_COMMAND) || (error.domain == MONGOC_ERROR_BSON && error.code == MONGOC_ERROR_BSON_INVALID))) { fprintf (stderr, "Expected error domain %d, or domain %d with code %d.\n" "Got domain %d, code %d, message: \"%s\"\n", MONGOC_ERROR_COMMAND, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, error.domain, error.code, error.message); fflush (stderr); abort (); } ASSERT_MATCH (&reply, "{'nInserted': 1," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [{'index': 1}]}"); assert_error_count (1, &reply); check_n_modified (has_write_cmds, &reply, 0); ASSERT_COUNT (1, collection); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, NULL); while (mongoc_cursor_next (cursor, &retdoc)) { ok++; } ASSERT_CMPINT (ok, ==, 1); if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "ERROR: %s\n", error.message); ASSERT (false); } bson_destroy (&query); mongoc_collection_remove (collection, MONGOC_REMOVE_NONE, tmp_bson ("{}"), NULL, NULL); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); assert (bulk); big_doc = tmp_bson ("{'a': 1}"); bson_append_utf8 (big_doc, "big", -1, four_mb_string (), (int) gFourMB); bson_iter_init_find (&iter, big_doc, "a"); for (i = 1; i <= 6; i++) { bson_iter_overwrite_int32 (&iter, i); mongoc_bulk_operation_insert (bulk, big_doc); } ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); assert_n_inserted (6, &reply); ASSERT_COUNT (6, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); bson_destroy (huge_doc); mongoc_client_destroy (client); } static void test_large_inserts_unordered (void) { mongoc_client_t *client; bson_t *huge_doc; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; bool r; bson_t *big_doc; bson_iter_t iter; int i; const bson_t *retdoc; bson_t query = BSON_INITIALIZER; mongoc_cursor_t *cursor; int ok = 0; client = test_framework_client_new (); assert (client); huge_doc = BCON_NEW ("a", BCON_INT32 (1)); bson_append_utf8 (huge_doc, "long-key-to-make-this-fail", -1, huge_string (client), (int) huge_string_length (client)); collection = get_test_collection (client, "test_large_inserts_unordered"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); assert (bulk); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 1, 'a': 1}")); /* 1 fails */ mongoc_bulk_operation_insert (bulk, huge_doc); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'b': 2, 'a': 2}")); r = (bool)mongoc_bulk_operation_execute (bulk, &reply, &error); assert (!r); /* TODO: CDRIVER-662, should always be MONGOC_ERROR_BSON */ assert ((error.domain == MONGOC_ERROR_COMMAND) || (error.domain == MONGOC_ERROR_BSON && error.code == MONGOC_ERROR_BSON_INVALID)); ASSERT_MATCH (&reply, "{'nInserted': 2," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [{" " 'index': 1," " 'code': {'$exists': true}," " 'errmsg': {'$exists': true}" " }]}"); ASSERT_COUNT (2, collection); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, NULL); while (mongoc_cursor_next (cursor, &retdoc)) { ok++; } ASSERT_CMPINT (ok, ==, 2); if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "ERROR: %s\n", error.message); ASSERT (false); } bson_destroy (&query); mongoc_collection_remove (collection, MONGOC_REMOVE_NONE, tmp_bson ("{}"), NULL, NULL); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); bulk = mongoc_collection_create_bulk_operation (collection, false, NULL); assert (bulk); big_doc = tmp_bson ("{'a': 1}"); bson_append_utf8 (big_doc, "big", -1, four_mb_string (), (int) gFourMB); bson_iter_init_find (&iter, big_doc, "a"); for (i = 1; i <= 6; i++) { bson_iter_overwrite_int32 (&iter, i); mongoc_bulk_operation_insert (bulk, big_doc); } ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); assert_n_inserted (6, &reply); ASSERT_COUNT (6, collection); bson_destroy (huge_doc); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void _test_numerous (bool ordered) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t reply; bson_error_t error; int n_docs = 4100; /* exceeds max write batch size of 1000 */ bson_t doc; bson_iter_t iter; int i; client = test_framework_client_new (); assert (client); collection = get_test_collection (client, "test_numerous_inserts"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); /* insert docs {_id: 0} through {_id: n_docs-1} */ bson_init (&doc); BSON_APPEND_INT32 (&doc, "_id", 0); bson_iter_init_find (&iter, &doc, "_id"); for (i = 0; i < n_docs; i++) { bson_iter_overwrite_int32 (&iter, i); mongoc_bulk_operation_insert (bulk, &doc); } ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); assert_n_inserted (n_docs, &reply); ASSERT_COUNT (n_docs, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); /* use remove_one for docs {_id: 0}, {_id: 2}, ..., {_id: n_docs-2} */ for (i = 0; i < n_docs; i += 2) { bson_iter_overwrite_int32 (&iter, i); mongoc_bulk_operation_remove_one (bulk, &doc); } ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); assert_n_removed (n_docs / 2, &reply); ASSERT_COUNT (n_docs / 2, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); /* use remove for docs {_id: 1}, {_id: 3}, ..., {_id: n_docs-1} */ for (i = 1; i < n_docs; i += 2) { bson_iter_overwrite_int32 (&iter, i); mongoc_bulk_operation_remove (bulk, &doc); } ASSERT_OR_PRINT ((bool)mongoc_bulk_operation_execute (bulk, &reply, &error), error); assert_n_removed (n_docs / 2, &reply); ASSERT_COUNT (0, collection); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_numerous_ordered (void) { _test_numerous (true); } static void test_numerous_unordered (void) { _test_numerous (false); } static void test_bulk_edge_over_1000 (void) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_bulk_operation_t * bulk_op; mongoc_write_concern_t * wc = mongoc_write_concern_new(); bson_iter_t iter, error_iter, indexnum; bson_t doc, result; bson_error_t error; int i; client = test_framework_client_new (); assert (client); collection = get_test_collection (client, "OVER_1000"); assert (collection); mongoc_write_concern_set_w(wc, 1); bulk_op = mongoc_collection_create_bulk_operation(collection, false, wc); for (i = 0; i < 1010; i+=3) { bson_init(&doc); bson_append_int32(&doc, "_id", -1, i); mongoc_bulk_operation_insert(bulk_op, &doc); bson_destroy(&doc); } mongoc_bulk_operation_execute(bulk_op, NULL, &error); mongoc_bulk_operation_destroy(bulk_op); bulk_op = mongoc_collection_create_bulk_operation(collection, false, wc); for (i = 0; i < 1010; i++) { bson_init(&doc); bson_append_int32(&doc, "_id", -1, i); mongoc_bulk_operation_insert(bulk_op, &doc); bson_destroy(&doc); } mongoc_bulk_operation_execute(bulk_op, &result, &error); bson_iter_init_find(&iter, &result, "writeErrors"); assert(bson_iter_recurse(&iter, &error_iter)); assert(bson_iter_next(&error_iter)); for (i = 0; i < 1010; i+=3) { assert(bson_iter_recurse(&error_iter, &indexnum)); assert(bson_iter_find(&indexnum, "index")); if (bson_iter_int32(&indexnum) != i) { fprintf(stderr, "index should be %d, but is %d\n", i, bson_iter_int32(&indexnum)); } assert(bson_iter_int32(&indexnum) == i); bson_iter_next(&error_iter); } mongoc_bulk_operation_destroy(bulk_op); bson_destroy (&result); mongoc_write_concern_destroy(wc); mongoc_collection_destroy(collection); mongoc_client_destroy(client); } static void test_bulk_edge_case_372 (bool ordered) { mongoc_client_t *client; bool has_write_cmds; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_error_t error; bson_iter_t iter; bson_iter_t citer; bson_t *selector; bson_t *update; bson_t reply; client = test_framework_client_new (); assert (client); has_write_cmds = server_has_write_commands (client); collection = get_test_collection (client, "CDRIVER_372"); assert (collection); bulk = mongoc_collection_create_bulk_operation (collection, ordered, NULL); assert (bulk); selector = tmp_bson ("{'_id': 0}"); update = tmp_bson ("{'$set': {'a': 0}}"); mongoc_bulk_operation_update_one (bulk, selector, update, true); selector = tmp_bson ("{'a': 1}"); update = tmp_bson ("{'_id': 1}"); mongoc_bulk_operation_replace_one (bulk, selector, update, true); if (has_write_cmds) { /* This is just here to make the counts right in all cases. */ selector = tmp_bson ("{'_id': 2}"); update = tmp_bson ("{'_id': 2}"); mongoc_bulk_operation_replace_one (bulk, selector, update, true); } else { /* This case is only possible in MongoDB versions before 2.6. */ selector = tmp_bson ("{'_id': 3}"); update = tmp_bson ("{'_id': 2}"); mongoc_bulk_operation_replace_one (bulk, selector, update, true); } ASSERT_OR_PRINT (mongoc_bulk_operation_execute (bulk, &reply, &error), error); ASSERT_MATCH (&reply, "{'nInserted': 0," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 3," " 'upserted': [" " {'index': 0, '_id': 0}," " {'index': 1, '_id': 1}," " {'index': 2, '_id': 2}" " ]," " 'writeErrors': []}"); check_n_modified (has_write_cmds, &reply, 0); assert (bson_iter_init_find (&iter, &reply, "upserted") && BSON_ITER_HOLDS_ARRAY (&iter) && bson_iter_recurse (&iter, &citer)); bson_destroy (&reply); mongoc_collection_drop (collection, NULL); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_bulk_edge_case_372_ordered (void) { test_bulk_edge_case_372 (true); } static void test_bulk_edge_case_372_unordered (void) { test_bulk_edge_case_372 (false); } static void test_bulk_new (void) { mongoc_bulk_operation_t *bulk; mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; bson_t empty = BSON_INITIALIZER; uint32_t r; client = test_framework_client_new (); assert (client); collection = get_test_collection (client, "bulk_new"); assert (collection); bulk = mongoc_bulk_operation_new (true); mongoc_bulk_operation_destroy (bulk); bulk = mongoc_bulk_operation_new (true); r = mongoc_bulk_operation_execute (bulk, NULL, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_COMMAND); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_COMMAND_INVALID_ARG); mongoc_bulk_operation_set_database (bulk, "test"); r = mongoc_bulk_operation_execute (bulk, NULL, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_COMMAND); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_COMMAND_INVALID_ARG); mongoc_bulk_operation_set_collection (bulk, "test"); r = mongoc_bulk_operation_execute (bulk, NULL, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_COMMAND); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_COMMAND_INVALID_ARG); mongoc_bulk_operation_set_client (bulk, client); r = mongoc_bulk_operation_execute (bulk, NULL, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_COMMAND); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_COMMAND_INVALID_ARG); mongoc_bulk_operation_insert (bulk, &empty); ASSERT_OR_PRINT (mongoc_bulk_operation_execute (bulk, NULL, &error), error); mongoc_bulk_operation_destroy (bulk); mongoc_collection_drop (collection, NULL); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } typedef enum { INSERT, UPDATE, REMOVE } op_type_t; static void _test_legacy_write_err (op_type_t op_type) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_t *doc = tmp_bson ("{'_id': 1}"); bson_t reply; bson_error_t error; future_t *future; request_t *request = NULL; server = mock_server_with_autoismaster (0); /* wire version = 0 */ mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "test", "test"); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); switch (op_type) { case INSERT: mongoc_bulk_operation_insert (bulk, doc); break; case UPDATE: mongoc_bulk_operation_update (bulk, doc, tmp_bson ( "{'$inc': {'x': 1}}"), false); break; case REMOVE: mongoc_bulk_operation_remove (bulk, doc); break; default: fprintf (stderr, "Invalid op_type: : %d\n", op_type); abort (); } future = future_bulk_operation_execute (bulk, &reply, &error); switch (op_type) { case INSERT: request = mock_server_receives_insert (server, "test.test", MONGOC_INSERT_NONE, "{'_id': 1}"); break; case UPDATE: request = mock_server_receives_update (server, "test.test", MONGOC_UPDATE_MULTI_UPDATE, "{'_id': 1}", "{'$inc': {'x': 1}}"); break; case REMOVE: request = mock_server_receives_delete (server, "test.test", MONGOC_REMOVE_NONE, "{'_id': 1}"); break; default: fprintf (stderr, "Invalid op_type: : %d\n", op_type); abort (); } request_destroy (request); request = mock_server_receives_gle (server, "test"); mock_server_hangs_up (request); request_destroy (request); /* bulk operation fails */ assert (!future_get_uint32_t (future)); future_destroy (future); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } static void test_legacy_insert_err (void) { _test_legacy_write_err (INSERT); } static void test_legacy_update_err (void) { _test_legacy_write_err (UPDATE); } static void test_legacy_remove_err (void) { _test_legacy_write_err (REMOVE); } static void test_bulk_write_concern_over_1000(void) { mongoc_client_t *client; mongoc_bulk_operation_t *bulk; mongoc_write_concern_t *write_concern; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_t doc; bson_error_t error; uint32_t success; int i; char *str; bson_t *query; const bson_t *result; bool r; client = test_framework_client_new (); assert (client); write_concern = mongoc_write_concern_new(); mongoc_write_concern_set_w (write_concern, 1); mongoc_client_set_write_concern (client, write_concern); str = gen_collection_name ("bulk_write_concern_over_1000"); bulk = mongoc_bulk_operation_new (true); mongoc_bulk_operation_set_database (bulk, "test"); mongoc_bulk_operation_set_collection (bulk, str); mongoc_write_concern_set_w (write_concern, 0); mongoc_bulk_operation_set_write_concern (bulk, write_concern); mongoc_bulk_operation_set_client (bulk, client); for (i = 0; i < 1010; i+=3) { bson_init(&doc); bson_append_int32(&doc, "_id", -1, i); mongoc_bulk_operation_insert(bulk, &doc); bson_destroy(&doc); } success = mongoc_bulk_operation_execute(bulk, NULL, &error); ASSERT_OR_PRINT (success, error); collection = mongoc_client_get_collection (client, "test", str); bson_free (str); query = bson_new(); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL); r = mongoc_cursor_next (cursor, &result); if (!r) { mongoc_cursor_error(cursor, &error); fprintf(stderr, "%s", error.message); } assert(r); bson_destroy (query); mongoc_cursor_destroy (cursor); mongoc_bulk_operation_destroy(bulk); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_write_concern_destroy (write_concern); } static uint32_t hint_for_read_mode (mongoc_client_t *client, mongoc_read_mode_t read_mode) { mongoc_read_prefs_t *prefs; mongoc_server_description_t *sd; bson_error_t error; uint32_t hint; prefs = mongoc_read_prefs_new (read_mode); sd = mongoc_topology_select (client->topology, MONGOC_SS_READ, prefs, 15, &error); ASSERT_OR_PRINT (sd, error); hint = sd->id; mongoc_server_description_destroy (sd); mongoc_read_prefs_destroy (prefs); return hint; } static void _test_bulk_hint (bool pooled, bool has_write_cmds, bool use_primary) { mock_rs_t *rs; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bool ret; uint32_t hint; bson_t reply; bson_error_t error; future_t *future; request_t *request; /* primary, 2 secondaries. set wire version for legacy writes / write cmds */ rs = mock_rs_with_autoismaster (has_write_cmds ? 3 : 0, true, 2, 0); mock_rs_run (rs); if (pooled) { pool = mongoc_client_pool_new (mock_rs_get_uri (rs)); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new_from_uri (mock_rs_get_uri (rs)); } /* warm up the client so its hint is valid */ ret = mongoc_client_command_simple (client, "admin", tmp_bson ("{'isMaster': 1}"), NULL, NULL, &error); ASSERT_OR_PRINT (ret, error); collection = mongoc_client_get_collection (client, "test", "test"); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); if (use_primary) { hint = hint_for_read_mode (client, MONGOC_READ_PRIMARY); } else { hint = hint_for_read_mode (client, MONGOC_READ_SECONDARY); } mongoc_bulk_operation_set_hint (bulk, hint); mongoc_bulk_operation_insert (bulk, tmp_bson ("{'_id': 1}")); future = future_bulk_operation_execute (bulk, &reply, &error); if (has_write_cmds) { request = mock_rs_receives_command (rs, "test", MONGOC_QUERY_NONE, "{'insert': 'test'}"); BSON_ASSERT (request); mock_server_replies_simple (request, "{'ok': 1.0, 'n': 1}"); } else { request = mock_rs_receives_insert (rs, "test.test", MONGOC_INSERT_NONE, "{'_id': 1}"); BSON_ASSERT (request); request_destroy (request); request = mock_rs_receives_command (rs, "test", MONGOC_QUERY_NONE, "{'getLastError': 1}"); BSON_ASSERT (request); mock_server_replies_simple (request, "{'ok': 1.0, 'n': 1}"); } if (use_primary) { BSON_ASSERT (mock_rs_request_is_to_primary (rs, request)); } else { BSON_ASSERT (mock_rs_request_is_to_secondary (rs, request)); } ASSERT_CMPINT (hint, ==, future_get_uint32_t (future)); request_destroy (request); future_destroy (future); bson_destroy (&reply); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } mock_rs_destroy (rs); } static void test_hint_single_legacy_secondary (void) { _test_bulk_hint (false, false, false); } static void test_hint_single_legacy_primary (void) { _test_bulk_hint (false, false, true); } static void test_hint_single_command_secondary (void) { _test_bulk_hint (false, true, false); } static void test_hint_single_command_primary (void) { _test_bulk_hint (false, true, true); } static void test_hint_pooled_legacy_secondary (void) { _test_bulk_hint (true, false, false); } static void test_hint_pooled_legacy_primary (void) { _test_bulk_hint (true, false, true); } static void test_hint_pooled_command_secondary (void) { _test_bulk_hint (true, true, false); } static void test_hint_pooled_command_primary (void) { _test_bulk_hint (true, true, true); } void test_bulk_install (TestSuite *suite) { atexit (test_bulk_cleanup); TestSuite_Add (suite, "/BulkOperation/basic", test_bulk); TestSuite_Add (suite, "/BulkOperation/insert_ordered", test_insert_ordered); TestSuite_Add (suite, "/BulkOperation/insert_unordered", test_insert_unordered); TestSuite_Add (suite, "/BulkOperation/insert_check_keys", test_insert_check_keys); TestSuite_Add (suite, "/BulkOperation/update_ordered", test_update_ordered); TestSuite_Add (suite, "/BulkOperation/update_unordered", test_update_unordered); TestSuite_Add (suite, "/BulkOperation/upsert_ordered", test_upsert_ordered); TestSuite_Add (suite, "/BulkOperation/upsert_unordered", test_upsert_unordered); TestSuite_Add (suite, "/BulkOperation/upsert_large", test_upsert_large); TestSuite_Add (suite, "/BulkOperation/upserted_index_ordered", test_upserted_index_ordered); TestSuite_Add (suite, "/BulkOperation/upserted_index_unordered", test_upserted_index_unordered); TestSuite_Add (suite, "/BulkOperation/update_one_ordered", test_update_one_ordered); TestSuite_Add (suite, "/BulkOperation/update_one_unordered", test_update_one_unordered); TestSuite_Add (suite, "/BulkOperation/replace_one_ordered", test_replace_one_ordered); TestSuite_Add (suite, "/BulkOperation/replace_one_unordered", test_replace_one_unordered); TestSuite_Add (suite, "/BulkOperation/index_offset", test_index_offset); TestSuite_Add (suite, "/BulkOperation/single_ordered_bulk", test_single_ordered_bulk); TestSuite_Add (suite, "/BulkOperation/insert_continue_on_error", test_insert_continue_on_error); TestSuite_Add (suite, "/BulkOperation/update_continue_on_error", test_update_continue_on_error); TestSuite_Add (suite, "/BulkOperation/remove_continue_on_error", test_remove_continue_on_error); TestSuite_Add (suite, "/BulkOperation/single_error_ordered_bulk", test_single_error_ordered_bulk); TestSuite_Add (suite, "/BulkOperation/multiple_error_ordered_bulk", test_multiple_error_ordered_bulk); TestSuite_Add (suite, "/BulkOperation/single_unordered_bulk", test_single_unordered_bulk); TestSuite_Add (suite, "/BulkOperation/single_error_unordered_bulk", test_single_error_unordered_bulk); TestSuite_Add (suite, "/BulkOperation/write_concern/legacy/ordered", test_write_concern_legacy_ordered); TestSuite_Add (suite, "/BulkOperation/write_concern/legacy/ordered/multi_err", test_write_concern_legacy_ordered_multi_err); TestSuite_Add (suite, "/BulkOperation/write_concern/legacy/unordered", test_write_concern_legacy_unordered); TestSuite_Add (suite, "/BulkOperation/write_concern/legacy/unordered/multi_err", test_write_concern_legacy_unordered_multi_err); TestSuite_Add (suite, "/BulkOperation/write_concern/write_command/ordered", test_write_concern_write_command_ordered); TestSuite_Add (suite, "/BulkOperation/write_concern/write_command/ordered/multi_err", test_write_concern_write_command_ordered_multi_err); TestSuite_Add (suite, "/BulkOperation/write_concern/write_command/unordered", test_write_concern_write_command_unordered); TestSuite_Add (suite, "/BulkOperation/write_concern/write_command/unordered/multi_err", test_write_concern_write_command_unordered_multi_err); TestSuite_Add (suite, "/BulkOperation/multiple_error_unordered_bulk", test_multiple_error_unordered_bulk); TestSuite_Add (suite, "/BulkOperation/wtimeout_duplicate_key/legacy", test_wtimeout_plus_duplicate_key_err_legacy); TestSuite_Add (suite, "/BulkOperation/wtimeout_duplicate_key/write_commands", test_wtimeout_plus_duplicate_key_err_write_commands); TestSuite_Add (suite, "/BulkOperation/large_inserts_ordered", test_large_inserts_ordered); TestSuite_Add (suite, "/BulkOperation/large_inserts_unordered", test_large_inserts_unordered); TestSuite_Add (suite, "/BulkOperation/numerous_ordered", test_numerous_ordered); TestSuite_Add (suite, "/BulkOperation/numerous_unordered", test_numerous_unordered); TestSuite_Add (suite, "/BulkOperation/CDRIVER-372_ordered", test_bulk_edge_case_372_ordered); TestSuite_Add (suite, "/BulkOperation/CDRIVER-372_unordered", test_bulk_edge_case_372_unordered); TestSuite_Add (suite, "/BulkOperation/new", test_bulk_new); TestSuite_Add (suite, "/BulkOperation/over_1000", test_bulk_edge_over_1000); TestSuite_Add (suite, "/BulkOperation/write_concern/over_1000", test_bulk_write_concern_over_1000); TestSuite_Add (suite, "/BulkOperation/error/insert", test_legacy_insert_err); TestSuite_Add (suite, "/BulkOperation/error/update", test_legacy_update_err); TestSuite_Add (suite, "/BulkOperation/error/remove", test_legacy_remove_err); TestSuite_Add (suite, "/BulkOperation/hint/single/legacy/secondary", test_hint_single_legacy_secondary); TestSuite_Add (suite, "/BulkOperation/hint/single/legacy/primary", test_hint_single_legacy_primary); TestSuite_Add (suite, "/BulkOperation/hint/single/command/secondary", test_hint_single_command_secondary); TestSuite_Add (suite, "/BulkOperation/hint/single/command/primary", test_hint_single_command_primary); TestSuite_Add (suite, "/BulkOperation/hint/pooled/legacy/secondary", test_hint_pooled_legacy_secondary); TestSuite_Add (suite, "/BulkOperation/hint/pooled/legacy/primary", test_hint_pooled_legacy_primary); TestSuite_Add (suite, "/BulkOperation/hint/pooled/command/secondary", test_hint_pooled_command_secondary); TestSuite_Add (suite, "/BulkOperation/hint/pooled/command/primary", test_hint_pooled_command_primary); } libmongoc-1.3.1/tests/test-conveniences.c000066400000000000000000000371711264720626300204500ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-array-private.h" #include "mongoc-util-private.h" #include "test-conveniences.h" static bool gConveniencesInitialized = false; static mongoc_array_t gTmpBsonArray; static void test_conveniences_cleanup (); static void test_conveniences_init () { if (!gConveniencesInitialized) { _mongoc_array_init (&gTmpBsonArray, sizeof (bson_t *)); atexit (test_conveniences_cleanup); gConveniencesInitialized = true; } } static void test_conveniences_cleanup () { int i; bson_t *doc; if (gConveniencesInitialized) { for (i = 0; i < gTmpBsonArray.len; i++) { doc = _mongoc_array_index (&gTmpBsonArray, bson_t *, i); bson_destroy (doc); } _mongoc_array_destroy (&gTmpBsonArray); } } bson_t * tmp_bson (const char *json) { bson_error_t error; char *double_quoted; bson_t *doc; test_conveniences_init (); if (json) { double_quoted = single_quotes_to_double (json); doc = bson_new_from_json ((const uint8_t *) double_quoted, -1, &error); if (!doc) { fprintf (stderr, "%s\n", error.message); abort (); } bson_free (double_quoted); } else { doc = bson_new (); } _mongoc_array_append_val (&gTmpBsonArray, doc); return doc; } /*-------------------------------------------------------------------------- * * bson_iter_bson -- * * Statically init a bson_t from an iter at an array or document. * *-------------------------------------------------------------------------- */ void bson_iter_bson (const bson_iter_t *iter, bson_t *bson) { uint32_t len; const uint8_t *data; assert (BSON_ITER_HOLDS_DOCUMENT (iter) || BSON_ITER_HOLDS_ARRAY (iter)); if (BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_iter_document (iter, &len, &data); } else { bson_iter_array (iter, &len, &data); } assert (bson_init_static (bson, data, len)); } static bool get_exists_operator (const bson_value_t *value, bool *exists); static bool get_empty_operator (const bson_value_t *value, bool *exists); static bool is_empty_doc_or_array (const bson_value_t *value); static bool find (bson_value_t *value, const bson_iter_t *iter, const char *key, bool is_command, bool is_first); static bool match_bson_value (const bson_value_t *doc, const bson_value_t *pattern); /*-------------------------------------------------------------------------- * * single_quotes_to_double -- * * Copy str with single-quotes replaced by double. * * Returns: * A string you must bson_free. * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * single_quotes_to_double (const char *str) { char *result = bson_strdup (str); char *p; for (p = result; *p; p++) { if (*p == '\'') { *p = '"'; } } return result; } /*-------------------------------------------------------------------------- * * match_json -- * * Call match_bson on "doc" and "json_pattern". * For convenience, single-quotes are synonymous with double-quotes. * * A NULL doc or NULL json_pattern means "{}". * * Returns: * True or false. * * Side effects: * Logs if no match. * *-------------------------------------------------------------------------- */ bool match_json (const bson_t *doc, bool is_command, const char *filename, int lineno, const char *funcname, const char *json_pattern, ...) { va_list args; char *json_pattern_formatted; char *double_quoted; bson_error_t error; bson_t *pattern; bool matches; va_start (args, json_pattern); json_pattern_formatted = bson_strdupv_printf ( json_pattern ? json_pattern : "{}", args); va_end (args); double_quoted = single_quotes_to_double (json_pattern_formatted); pattern = bson_new_from_json ((const uint8_t *) double_quoted, -1, &error); if (!pattern) { fprintf (stderr, "couldn't parse JSON: %s\n", error.message); abort (); } matches = match_bson (doc, pattern, is_command); if (!matches) { fprintf (stderr, "ASSERT_MATCH failed with document:\n\n" "%s\n" "pattern:\n%s\n\n" "%s:%d %s()\n", doc ? bson_as_json (doc, NULL) : "{}", double_quoted, filename, lineno, funcname); } bson_destroy (pattern); bson_free (json_pattern_formatted); bson_free (double_quoted); return matches; } /*-------------------------------------------------------------------------- * * match_bson -- * * Does "doc" match "pattern"? * * mongoc_matcher_t prohibits $-prefixed keys, which is something * we need to test in e.g. test_mongoc_client_read_prefs, so this * does *not* use mongoc_matcher_t. Instead, "doc" matches "pattern" * if its key-value pairs are a simple superset of pattern's. Order * matters. * * The only special pattern syntaxes are "field": {"$exists": true/false} * and "field": {"$empty": true/false}. * * The first key matches case-insensitively if is_command. * * A NULL doc or NULL pattern means "{}". * * Returns: * True or false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool match_bson (const bson_t *doc, const bson_t *pattern, bool is_command) { bson_iter_t pattern_iter; const char *key; const bson_value_t *value; bson_iter_t doc_iter; bool is_first = true; bool is_exists_operator; bool is_empty_operator; bool exists; bool empty; bool found; bson_value_t doc_value; if (bson_empty0 (pattern)) { /* matches anything */ return true; } if (bson_empty0 (doc)) { /* non-empty pattern can't match doc */ return false; } assert (bson_iter_init (&pattern_iter, pattern)); assert (bson_iter_init (&doc_iter, doc)); while (bson_iter_next (&pattern_iter)) { key = bson_iter_key (&pattern_iter); value = bson_iter_value (&pattern_iter); found = find (&doc_value, &doc_iter, key, is_command, is_first); /* is value {"$exists": true} or {"$exists": false} ? */ is_exists_operator = get_exists_operator (value, &exists); /* is value {"$empty": true} or {"$empty": false} ? */ is_empty_operator = get_empty_operator (value, &empty); if (is_exists_operator) { if (exists != found) { return false; } } else if (!found) { return false; } else if (is_empty_operator) { if (empty != is_empty_doc_or_array (&doc_value)) { return false; } } else if (!match_bson_value (&doc_value, value)) { return false; } /* don't advance if next call may be for another key in the same subdoc, * or if we're skipping a pattern key that was {$exists: false}. */ if (!strchr (key, '.') && !(is_exists_operator && !exists)) { bson_iter_next (&doc_iter); } is_first = false; if (found) { bson_value_destroy (&doc_value); } } return true; } /*-------------------------------------------------------------------------- * * find -- * * Find the value for a key. * * Returns: * Whether the key was found. * * Side effects: * Copies the found value into "value". * *-------------------------------------------------------------------------- */ static bool find (bson_value_t *value, const bson_iter_t *iter, const char *key, bool is_command, bool is_first) { bson_iter_t i2; bson_iter_t descendent; /* don't advance iter. */ memcpy (&i2, iter, sizeof *iter); if (strchr (key, '.')) { if (!bson_iter_find_descendant (&i2, key, &descendent)) { return false; } bson_value_copy(bson_iter_value (&descendent), value); return true; } else if (is_command && is_first) { if (!bson_iter_find_case (&i2, key)) { return false; } } else if (!bson_iter_find (&i2, key)) { return false; } bson_value_copy (bson_iter_value (&i2), value); return true; } static bool bson_init_from_value (bson_t *b, const bson_value_t *v) { assert (v->value_type == BSON_TYPE_ARRAY || v->value_type == BSON_TYPE_DOCUMENT); return bson_init_static (b, v->value.v_doc.data, v->value.v_doc.data_len); } static bool _is_operator (const char *op_name, const bson_value_t *value, bool *op_val) { bson_t bson; bson_iter_t iter; if (value->value_type == BSON_TYPE_DOCUMENT && bson_init_from_value (&bson, value) && bson_iter_init_find (&iter, &bson, op_name)) { *op_val = bson_iter_as_bool (&iter); return true; } return false; } /*-------------------------------------------------------------------------- * * get_exists_operator -- * * Is value a subdocument like {"$exists": bool}? * * Returns: * True if the value is a subdocument with the first key "$exists". * * Side effects: * If the function returns true, *exists is set to true or false, * the value of the bool. * *-------------------------------------------------------------------------- */ static bool get_exists_operator (const bson_value_t *value, bool *exists) { return _is_operator ("$exists", value, exists); } /*-------------------------------------------------------------------------- * * get_empty_operator -- * * Is value a subdocument like {"$empty": bool}? * * Returns: * True if the value is a subdocument with the first key "$empty". * * Side effects: * If the function returns true, *empty is set to true or false, * the value of the bool. * *-------------------------------------------------------------------------- */ bool get_empty_operator (const bson_value_t *value, bool *empty) { return _is_operator ("$empty", value, empty); } /*-------------------------------------------------------------------------- * * is_empty_doc_or_array -- * * Is value the subdocument {} or the array []? * *-------------------------------------------------------------------------- */ static bool is_empty_doc_or_array (const bson_value_t *value) { bson_t doc; if (!(value->value_type == BSON_TYPE_ARRAY || value->value_type == BSON_TYPE_DOCUMENT)) { return false; } assert (bson_init_static (&doc, value->value.v_doc.data, value->value.v_doc.data_len)); return bson_count_keys (&doc) == 0; } static bool match_bson_arrays (const bson_t *array, const bson_t *pattern) { /* an array is just a document with keys "0", "1", ... * so match_bson suffices if the number of keys is equal. */ if (bson_count_keys (array) != bson_count_keys (pattern)) { return false; } return match_bson (array, pattern, false); } static bool match_bson_value (const bson_value_t *doc, const bson_value_t *pattern) { bson_t subdoc; bson_t pattern_subdoc; bool ret; if (doc->value_type != pattern->value_type) { return false; } switch (doc->value_type) { case BSON_TYPE_ARRAY: case BSON_TYPE_DOCUMENT: if (!bson_init_from_value (&subdoc, doc)) { return false; } if (!bson_init_from_value (&pattern_subdoc, pattern)) { bson_destroy (&subdoc); return false; } if (doc->value_type == BSON_TYPE_ARRAY) { ret = match_bson_arrays (&subdoc, &pattern_subdoc); } else { ret = match_bson (&subdoc, &pattern_subdoc, false); } bson_destroy (&subdoc); bson_destroy (&pattern_subdoc); return ret; case BSON_TYPE_BINARY: return doc->value.v_binary.data_len == pattern->value.v_binary.data_len && !memcmp (doc->value.v_binary.data, pattern->value.v_binary.data, doc->value.v_binary.data_len); case BSON_TYPE_BOOL: return doc->value.v_bool == pattern->value.v_bool; case BSON_TYPE_CODE: return doc->value.v_code.code_len == pattern->value.v_code.code_len && !memcmp (doc->value.v_code.code, pattern->value.v_code.code, doc->value.v_code.code_len); case BSON_TYPE_CODEWSCOPE: return doc->value.v_codewscope.code_len == pattern->value.v_codewscope.code_len && !memcmp (doc->value.v_codewscope.code, pattern->value.v_codewscope.code, doc->value.v_codewscope.code_len) && doc->value.v_codewscope.scope_len == pattern->value.v_codewscope.scope_len && !memcmp (doc->value.v_codewscope.scope_data, pattern->value.v_codewscope.scope_data, doc->value.v_codewscope.scope_len); case BSON_TYPE_DATE_TIME: return doc->value.v_datetime == pattern->value.v_datetime; case BSON_TYPE_DOUBLE: return doc->value.v_double == pattern->value.v_double; case BSON_TYPE_INT32: return doc->value.v_int32 == pattern->value.v_int32; case BSON_TYPE_INT64: return doc->value.v_int64 == pattern->value.v_int64; case BSON_TYPE_OID: return bson_oid_equal (&doc->value.v_oid, &pattern->value.v_oid); case BSON_TYPE_REGEX: return !strcmp (doc->value.v_regex.regex, pattern->value.v_regex.regex) && !strcmp (doc->value.v_regex.options, pattern->value.v_regex.options); case BSON_TYPE_SYMBOL: return doc->value.v_symbol.len == pattern->value.v_symbol.len && !strncmp (doc->value.v_symbol.symbol, pattern->value.v_symbol.symbol, doc->value.v_symbol.len); case BSON_TYPE_TIMESTAMP: return doc->value.v_timestamp.timestamp == pattern->value.v_timestamp.timestamp && doc->value.v_timestamp.increment == pattern->value.v_timestamp.increment; case BSON_TYPE_UTF8: return doc->value.v_utf8.len == pattern->value.v_utf8.len && !strncmp (doc->value.v_utf8.str, pattern->value.v_utf8.str, doc->value.v_utf8.len); /* these are empty types, if "a" and "b" are the same type they're equal */ case BSON_TYPE_EOD: case BSON_TYPE_MAXKEY: case BSON_TYPE_MINKEY: case BSON_TYPE_NULL: case BSON_TYPE_UNDEFINED: return true; case BSON_TYPE_DBPOINTER: fprintf (stderr, "DBPointer comparison not implemented"); abort (); default: fprintf (stderr, "unexpected value type %d", doc->value_type); abort (); } } libmongoc-1.3.1/tests/test-conveniences.h000066400000000000000000000027331264720626300204510ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef TEST_CONVENIENCES_H #define TEST_CONVENIENCES_H #include #include "mongoc.h" bson_t *tmp_bson (const char *json); void bson_iter_bson (const bson_iter_t *iter, bson_t *bson); char *single_quotes_to_double (const char *str); bool match_bson (const bson_t *doc, const bson_t *pattern, bool is_command); bool match_json (const bson_t *doc, bool is_command, const char *filename, int lineno, const char *funcname, const char *json_pattern, ...); #define ASSERT_MATCH(doc, ...) \ do { \ assert (match_json (doc, false, \ __FILE__, __LINE__, BSON_FUNC, \ __VA_ARGS__)); \ } while (0) #endif /* TEST_CONVENIENCES_H */ libmongoc-1.3.1/tests/test-libmongoc.c000066400000000000000000001017161264720626300177370ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "mongoc-server-description.h" #include "mongoc-server-description-private.h" #include "mongoc-topology-private.h" #include "mongoc-client-private.h" #include "mongoc-uri-private.h" #include "mongoc-util-private.h" #include "mongoc-tests.h" #include "TestSuite.h" #include "test-conveniences.h" #include "test-libmongoc.h" extern void test_array_install (TestSuite *suite); extern void test_async_install (TestSuite *suite); extern void test_buffer_install (TestSuite *suite); extern void test_bulk_install (TestSuite *suite); extern void test_client_install (TestSuite *suite); extern void test_client_pool_install (TestSuite *suite); extern void test_cluster_install (TestSuite *suite); extern void test_collection_install (TestSuite *suite); extern void test_collection_find_install (TestSuite *suite); extern void test_cursor_install (TestSuite *suite); extern void test_database_install (TestSuite *suite); extern void test_exhaust_install (TestSuite *suite); extern void test_find_and_modify_install (TestSuite *suite); extern void test_gridfs_file_page_install (TestSuite *suite); extern void test_gridfs_install (TestSuite *suite); extern void test_list_install (TestSuite *suite); extern void test_log_install (TestSuite *suite); extern void test_matcher_install (TestSuite *suite); extern void test_queue_install (TestSuite *suite); extern void test_read_prefs_install (TestSuite *suite); extern void test_rpc_install (TestSuite *suite); extern void test_sdam_install (TestSuite *suite); extern void test_sasl_install (TestSuite *suite); extern void test_server_selection_install (TestSuite *suite); extern void test_server_selection_errors_install (TestSuite *suite); extern void test_set_install (TestSuite *suite); extern void test_socket_install (TestSuite *suite); extern void test_stream_install (TestSuite *suite); extern void test_thread_install (TestSuite *suite); extern void test_topology_install (TestSuite *suite); extern void test_topology_reconcile_install (TestSuite *suite); extern void test_topology_scanner_install (TestSuite *suite); extern void test_uri_install (TestSuite *suite); extern void test_usleep_install (TestSuite *suite); extern void test_version_install (TestSuite *suite); extern void test_write_command_install (TestSuite *suite); extern void test_write_concern_install (TestSuite *suite); #ifdef MONGOC_ENABLE_SSL extern void test_x509_install (TestSuite *suite); extern void test_stream_tls_install (TestSuite *suite); extern void test_stream_tls_error_install (TestSuite *suite); #endif static int gSuppressCount; #ifdef MONGOC_ENABLE_SSL static mongoc_ssl_opt_t gSSLOptions; #endif void suppress_one_message (void) { gSuppressCount++; } static void log_handler (mongoc_log_level_t log_level, const char *log_domain, const char *message, void *user_data) { if (log_level < MONGOC_LOG_LEVEL_INFO) { if (gSuppressCount) { gSuppressCount--; return; } mongoc_log_default_handler (log_level, log_domain, message, NULL); } } char MONGOC_TEST_UNIQUE [32]; char * gen_collection_name (const char *str) { return bson_strdup_printf ("%s_%u_%u", str, (unsigned)time(NULL), (unsigned)gettestpid()); } /* *-------------------------------------------------------------------------- * * test_framework_get_env -- * * Get the value of an environment variable. * * Returns: * A string you must bson_free, or NULL if the variable is not set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * test_framework_getenv (const char *name) { #ifdef _MSC_VER char buf[1024]; size_t buflen; if ((0 == getenv_s (&buflen, buf, sizeof buf, name)) && buflen) { return bson_strdup (buf); } else { return NULL; } #else if (getenv (name) && strlen (getenv (name))) { return bson_strdup (getenv (name)); } else { return NULL; } #endif } /* *-------------------------------------------------------------------------- * * test_framework_getenv_bool -- * * Check if an environment variable is set. * * Returns: * True if the variable is set, or set to "on", false if it is not set * or set to "off". * * Side effects: * Logs and aborts if there is another value like "yes" or "true". * *-------------------------------------------------------------------------- */ bool test_framework_getenv_bool (const char *name) { char *value = test_framework_getenv (name); bool ret = false; if (value) { if (!strcasecmp (value, "off")) { ret = false; } else if (!strcasecmp (value, "") || !strcasecmp (value, "on")) { ret = true; } else { fprintf (stderr, "Unrecognized value for %s: \"%s\". Use \"on\" or \"off\".\n", name, value); abort (); } } bson_free (value); return ret; } /* *-------------------------------------------------------------------------- * * test_framework_getenv_int64 -- * * Get a number from an environment variable. * * Returns: * The number, or default. * * Side effects: * Logs and aborts if there is a non-numeric value. * *-------------------------------------------------------------------------- */ int64_t test_framework_getenv_int64 (const char *name, int64_t default_value) { char *value = test_framework_getenv (name); char *endptr; int64_t ret; if (value) { errno = 0; ret = bson_ascii_strtoll (value, &endptr, 10); if (errno) { perror (bson_strdup_printf ("Parsing %s from environment", name)); abort (); } bson_free (value); return ret; } return default_value; } /* *-------------------------------------------------------------------------- * * test_framework_get_unix_domain_socket_path -- * * Get the path to Unix Domain Socket .sock of the test MongoDB server. * * Returns: * A string you must bson_free. * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * test_framework_get_unix_domain_socket_path (void) { char *path = test_framework_getenv ("MONGOC_TEST_UNIX_DOMAIN_SOCKET"); if (path) { return path; } return bson_strdup_printf ("%%2Ftmp%%2Fmongodb-%d.sock", test_framework_get_port()); } /* *-------------------------------------------------------------------------- * * test_framework_get_host -- * * Get the hostname of the test MongoDB server. * * Returns: * A string you must bson_free. * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * test_framework_get_host (void) { char *host = test_framework_getenv ("MONGOC_TEST_HOST"); return host ? host : bson_strdup ("localhost"); } /* *-------------------------------------------------------------------------- * * test_framework_get_port -- * * Get the port number of the test MongoDB server. * * Returns: * The port number, 27017 by default. * * Side effects: * None. * *-------------------------------------------------------------------------- */ uint16_t test_framework_get_port (void) { char *port_str = test_framework_getenv ("MONGOC_TEST_PORT"); unsigned long port = MONGOC_DEFAULT_PORT; if (port_str && strlen (port_str)) { port = strtoul (port_str, NULL, 10); if (port == 0 || port > UINT16_MAX) { /* parse err or port out of range -- mongod prohibits port 0 */ port = MONGOC_DEFAULT_PORT; } } bson_free (port_str); return (uint16_t) port; } /* *-------------------------------------------------------------------------- * * test_framework_get_admin_user -- * * Get the username of an admin user on the test MongoDB server. * * Returns: * A string you must bson_free, or NULL. * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * test_framework_get_admin_user (void) { return test_framework_getenv ("MONGOC_TEST_USER"); } /* *-------------------------------------------------------------------------- * * test_framework_get_admin_password -- * * Get the password of an admin user on the test MongoDB server. * * Returns: * A string you must bson_free, or NULL. * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * test_framework_get_admin_password (void) { return test_framework_getenv ("MONGOC_TEST_PASSWORD"); } /* *-------------------------------------------------------------------------- * * test_framework_get_user_password -- * * Get the username and password of an admin user on the test MongoDB * server. * * Returns: * True if username and password environment variables are set. * * Side effects: * Sets passed-in string pointers to strings you must free, or NULL. * Logs and aborts if user or password is set in the environment * but not both, or if user and password are set but SSL is not * compiled in (SSL is required for SCRAM-SHA-1, see CDRIVER-520). * *-------------------------------------------------------------------------- */ static bool test_framework_get_user_password (char **user, char **password) { /* TODO: uri-escape username and password */ *user = test_framework_get_admin_user (); *password = test_framework_get_admin_password (); if ((*user && !*password) || (!*user && *password)) { fprintf (stderr, "Specify both MONGOC_TEST_USER and" " MONGOC_TEST_PASSWORD, or neither\n"); abort (); } #ifndef MONGOC_ENABLE_SSL if (*user && *password) { fprintf (stderr, "You need to configure with --enable-ssl" " when providing user+password (for SCRAM-SHA-1)\n"); abort (); } #endif return *user != NULL; } /* *-------------------------------------------------------------------------- * * test_framework_add_user_password -- * * Copy a connection string, with user and password added. * * Returns: * A string you must bson_free. * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * test_framework_add_user_password (const char *uri_str, const char *user, const char *password) { return bson_strdup_printf ( "mongodb://%s:%s@%s", user, password, uri_str + strlen ("mongodb://")); } /* *-------------------------------------------------------------------------- * * test_framework_add_user_password_from_env -- * * Add password of an admin user on the test MongoDB server. * * Returns: * A string you must bson_free. * * Side effects: * Same as test_framework_get_user_password. * *-------------------------------------------------------------------------- */ char * test_framework_add_user_password_from_env (const char *uri_str) { char *user; char *password; char *uri_str_auth; if (test_framework_get_user_password (&user, &password)) { uri_str_auth = test_framework_add_user_password (uri_str, user, password); bson_free (user); bson_free (password); } else { uri_str_auth = bson_strdup (uri_str); } return uri_str_auth; } /* *-------------------------------------------------------------------------- * * test_framework_get_ssl -- * * Should we connect to the test MongoDB server over SSL? * * Returns: * True if any MONGOC_TEST_SSL_* environment variables are set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool test_framework_get_ssl (void) { char *ssl_option_names[] = { "MONGOC_TEST_SSL_PEM_FILE", "MONGOC_TEST_SSL_PEM_PWD", "MONGOC_TEST_SSL_CA_FILE", "MONGOC_TEST_SSL_CA_DIR", "MONGOC_TEST_SSL_CRL_FILE", "MONGOC_TEST_SSL_WEAK_CERT_VALIDATION" }; char *ssl_option_value; size_t i; for (i = 0; i < sizeof ssl_option_names / sizeof (char *); i++) { ssl_option_value = test_framework_getenv (ssl_option_names[i]); if (ssl_option_value) { bson_free (ssl_option_value); return true; } } return test_framework_getenv_bool ("MONGOC_TEST_SSL"); } /* *-------------------------------------------------------------------------- * * test_framework_get_unix_domain_socket_uri_str -- * * Get the connection string (unix domain socket style) of the test * MongoDB server based on the variables set in the environment. * Does *not* call isMaster to discover your actual topology. * * Returns: * A string you must bson_free. * * Side effects: * Same as test_framework_get_user_password. * *-------------------------------------------------------------------------- */ char * test_framework_get_unix_domain_socket_uri_str () { char *path; char *test_uri_str; char *test_uri_str_auth; path = test_framework_get_unix_domain_socket_path (); test_uri_str = bson_strdup_printf ( "mongodb://%s/%s", path, test_framework_get_ssl () ? "?ssl=true" : ""); test_uri_str_auth = test_framework_add_user_password_from_env (test_uri_str); bson_free (path); bson_free (test_uri_str); return test_uri_str_auth; } /* *-------------------------------------------------------------------------- * * call_ismaster_with_host_and_port -- * * Call isMaster on a server, possibly over SSL. * * Side effects: * Fills reply with ismaster response. Logs and aborts on error. * *-------------------------------------------------------------------------- */ static void call_ismaster_with_host_and_port (char *host, uint16_t port, bson_t *reply) { char *uri_str; mongoc_uri_t *uri; mongoc_client_t *client; bson_error_t error; uri_str = bson_strdup_printf ( "mongodb://%s:%hu%s", host, port, test_framework_get_ssl () ? "?ssl=true" : ""); uri = mongoc_uri_new (uri_str); assert (uri); mongoc_uri_set_option_as_int32 (uri, "connectTimeoutMS", 10000); mongoc_uri_set_option_as_int32 (uri, "serverSelectionTimeoutMS", 10000); mongoc_uri_set_option_as_bool (uri, "serverSelectionTryOnce", false); client = mongoc_client_new_from_uri (uri); test_framework_set_ssl_opts (client); if (!mongoc_client_command_simple (client, "admin", tmp_bson ("{'isMaster': 1}"), NULL, reply, &error)) { fprintf (stderr, "error calling ismaster: '%s'\n", error.message); fprintf (stderr, "URI = %s\n", uri_str); abort (); } mongoc_client_destroy (client); mongoc_uri_destroy (uri); bson_free (uri_str); } /* *-------------------------------------------------------------------------- * * call_ismaster -- * * Call isMaster on the test server, possibly over SSL, using host * and port from the environment. * * Side effects: * Fills reply with ismaster response. Logs and aborts on error. * *-------------------------------------------------------------------------- */ static void call_ismaster (bson_t *reply) { char *host; uint16_t port; host = test_framework_get_host (); port = test_framework_get_port (); call_ismaster_with_host_and_port (host, port, reply); bson_free (host); } static char * set_name (bson_t *ismaster_response) { bson_iter_t iter; if (bson_iter_init_find (&iter, ismaster_response, "setName")) { return bson_strdup (bson_iter_utf8 (&iter, NULL)); } else { return NULL; } } /* *-------------------------------------------------------------------------- * * test_framework_get_uri_str_no_auth -- * * Get the connection string of the test MongoDB topology -- * standalone, replica set, mongos, or mongoses -- along with * SSL options, but not username and password. Calls calls isMaster with * that connection string to discover your topology, and * returns an appropriate connection string for the topology * type. * * database_name is optional. * * Returns: * A string you must bson_free. * * Side effects: * Same as test_framework_get_user_password. * *-------------------------------------------------------------------------- */ char * test_framework_get_uri_str_no_auth (const char *database_name) { bson_t ismaster_response; bson_string_t *uri_string; char *name; bson_iter_t iter; bson_iter_t hosts_iter; bool first; char *host; uint16_t port; call_ismaster (&ismaster_response); uri_string = bson_string_new ("mongodb://"); if ((name = set_name (&ismaster_response))) { /* make a replica set URI */ bson_iter_init_find (&iter, &ismaster_response, "hosts"); bson_iter_recurse (&iter, &hosts_iter); first = true; /* append "host1,host2,host3" */ while (bson_iter_next (&hosts_iter)) { assert (BSON_ITER_HOLDS_UTF8 (&hosts_iter)); if (!first) { bson_string_append (uri_string, ","); } bson_string_append (uri_string, bson_iter_utf8 (&hosts_iter, NULL)); first = false; } bson_string_append (uri_string, "/"); if (database_name) { bson_string_append (uri_string, database_name); } bson_string_append_printf (uri_string, "?replicaSet=%s", name); bson_free (name); } else { host = test_framework_get_host (); port = test_framework_get_port (); bson_string_append_printf (uri_string, "%s:%hu", host, port); bson_string_append (uri_string, "/"); if (database_name) { bson_string_append (uri_string, database_name); } bson_free (host); } if (test_framework_get_ssl ()) { if (name) { /* string ends with "?replicaSet=name" */ bson_string_append (uri_string, "&ssl=true"); } else { /* string ends with "/" or "/dbname" */ bson_string_append (uri_string, "?ssl=true"); } } bson_destroy (&ismaster_response); return bson_string_free (uri_string, false); } /* *-------------------------------------------------------------------------- * * test_framework_get_uri_str -- * * Get the connection string of the test MongoDB topology -- * standalone, replica set, mongos, or mongoses -- along with * SSL options, username and password. * * Returns: * A string you must bson_free. * * Side effects: * Same as test_framework_get_user_password. * *-------------------------------------------------------------------------- */ char * test_framework_get_uri_str () { char *uri_str_no_auth; char *uri_str; uri_str_no_auth = test_framework_get_uri_str_no_auth (NULL); uri_str = test_framework_add_user_password_from_env (uri_str_no_auth); bson_free (uri_str_no_auth); return uri_str; } /* *-------------------------------------------------------------------------- * * test_framework_get_uri -- * * Like test_framework_get_uri_str (). Get the URI of the test * MongoDB server. * * Returns: * A mongoc_uri_t* you must destroy. * * Side effects: * Same as test_framework_get_user_password. * *-------------------------------------------------------------------------- */ mongoc_uri_t * test_framework_get_uri () { char *test_uri_str = test_framework_get_uri_str (); mongoc_uri_t *uri = mongoc_uri_new (test_uri_str); assert (uri); bson_free (test_uri_str); return uri; } /* *-------------------------------------------------------------------------- * * test_framework_set_ssl_opts -- * * Configure a client to connect to the test MongoDB server. * * Returns: * None. * * Side effects: * Logs and aborts if any MONGOC_TEST_SSL_* environment variables are * set but the driver is not built with SSL enabled. * *-------------------------------------------------------------------------- */ void test_framework_set_ssl_opts (mongoc_client_t *client) { assert (client); if (test_framework_get_ssl ()) { #ifndef MONGOC_ENABLE_SSL fprintf (stderr, "SSL test config variables are specified in the environment, but" " SSL isn't enabled\n"); abort (); #else mongoc_client_set_ssl_opts (client, &gSSLOptions); #endif } } /* *-------------------------------------------------------------------------- * * test_framework_client_new -- * * Get a client connected to the test MongoDB topology. * * Returns: * A client you must mongoc_client_destroy. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_client_t * test_framework_client_new () { char *test_uri_str = test_framework_get_uri_str (); mongoc_client_t *client = mongoc_client_new (test_uri_str); assert (client); test_framework_set_ssl_opts (client); bson_free (test_uri_str); return client; } #ifdef MONGOC_ENABLE_SSL /* *-------------------------------------------------------------------------- * * test_framework_get_ssl_opts -- * * Get options for connecting to mongod over SSL (even if mongod * isn't actually SSL-enabled). * * Returns: * A pointer to constant global SSL-test options. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_ssl_opt_t * test_framework_get_ssl_opts (void) { return &gSSLOptions; } #endif /* *-------------------------------------------------------------------------- * * test_framework_set_pool_ssl_opts -- * * Configure a client pool to connect to the test MongoDB server. * * Returns: * None. * * Side effects: * Logs and aborts if any MONGOC_TEST_SSL_* environment variables are * set but the driver is not built with SSL enabled. * *-------------------------------------------------------------------------- */ void test_framework_set_pool_ssl_opts (mongoc_client_pool_t *pool) { assert (pool); if (test_framework_get_ssl ()) { #ifndef MONGOC_ENABLE_SSL fprintf (stderr, "SSL test config variables are specified in the environment, but" " SSL isn't enabled\n"); abort (); #else mongoc_client_pool_set_ssl_opts (pool, &gSSLOptions); #endif } } /* *-------------------------------------------------------------------------- * * test_framework_pool_new -- * * Get a client pool connected to the test MongoDB topology. * * Returns: * A pool you must destroy. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_client_pool_t * test_framework_client_pool_new () { mongoc_uri_t *test_uri = test_framework_get_uri (); mongoc_client_pool_t *pool = mongoc_client_pool_new (test_uri); assert (pool); test_framework_set_pool_ssl_opts (pool); mongoc_uri_destroy (test_uri); assert (pool); return pool; } #ifdef MONGOC_ENABLE_SSL static void test_framework_global_ssl_opts_init (void) { memcpy (&gSSLOptions, mongoc_ssl_opt_get_default (), sizeof gSSLOptions); gSSLOptions.pem_file = test_framework_getenv ("MONGOC_TEST_SSL_PEM_FILE"); gSSLOptions.pem_pwd = test_framework_getenv ("MONGOC_TEST_SSL_PEM_PWD"); gSSLOptions.ca_file = test_framework_getenv ("MONGOC_TEST_SSL_CA_FILE"); gSSLOptions.ca_dir = test_framework_getenv ("MONGOC_TEST_SSL_CA_DIR"); gSSLOptions.crl_file = test_framework_getenv ("MONGOC_TEST_SSL_CRL_FILE"); gSSLOptions.weak_cert_validation = test_framework_getenv_bool ( "MONGOC_TEST_SSL_WEAK_CERT_VALIDATION"); } static void test_framework_global_ssl_opts_cleanup (void) { bson_free ((void *)gSSLOptions.pem_file); bson_free ((void *)gSSLOptions.pem_pwd); bson_free ((void *)gSSLOptions.ca_file); bson_free ((void *)gSSLOptions.ca_dir); bson_free ((void *)gSSLOptions.crl_file); } #endif bool test_framework_is_mongos (void) { bson_t reply; bson_iter_t iter; bool is_mongos; call_ismaster (&reply); is_mongos = (bson_iter_init_find (&iter, &reply, "msg") && BSON_ITER_HOLDS_UTF8 (&iter) && !strcasecmp (bson_iter_utf8 (&iter, NULL), "isdbgrid")); bson_destroy (&reply); return is_mongos; } bool test_framework_is_replset (void) { bson_t reply; bson_iter_t iter; bool is_replset; call_ismaster (&reply); is_replset = (bson_iter_init_find (&iter, &reply, "hosts") && BSON_ITER_HOLDS_ARRAY (&iter)); bson_destroy (&reply); return is_replset; } bool test_framework_server_is_secondary (mongoc_client_t *client, uint32_t server_id) { bson_t reply; bson_iter_t iter; mongoc_server_description_t *sd; bson_error_t error; bool ret; sd = mongoc_topology_server_by_id (client->topology, server_id, &error); ASSERT_OR_PRINT (sd, error); call_ismaster_with_host_and_port (sd->host.host, sd->host.port, &reply); ret = bson_iter_init_find (&iter, &reply, "secondary") && bson_iter_as_bool (&iter); mongoc_server_description_destroy (sd); return ret; } int test_framework_skip_if_windows (void) { #ifdef _WIN32 return false; #else return true; #endif } bool test_framework_max_wire_version_at_least (int version) { bson_t reply; bson_iter_t iter; bool at_least; call_ismaster (&reply); at_least = (bson_iter_init_find (&iter, &reply, "maxWireVersion") && bson_iter_as_int64 (&iter) >= version); bson_destroy (&reply); return at_least; } #define N_SERVER_VERSION_PARTS 4 static server_version_t _parse_server_version (const bson_t *buildinfo) { bson_iter_t iter; bson_iter_t array_iter; int i; server_version_t ret = 0; ASSERT (bson_iter_init_find (&iter, buildinfo, "versionArray")); ASSERT (bson_iter_recurse (&iter, &array_iter)); /* Server returns a 4-part version like [3, 2, 0, 0], or like [3, 2, 0, -49] * for an RC. Bail if number of parts is ever not 4. */ i = 0; while (bson_iter_next (&array_iter)) { ret *= 1000; ret += 100 + bson_iter_as_int64 (&array_iter); i++; ASSERT_CMPINT (i, <=, N_SERVER_VERSION_PARTS); } ASSERT_CMPINT (i, ==, N_SERVER_VERSION_PARTS); return ret; } server_version_t test_framework_get_server_version (void) { mongoc_client_t *client; bson_t reply; bson_error_t error; server_version_t ret = 0; client = test_framework_client_new (); ASSERT_OR_PRINT (mongoc_client_command_simple ( client, "admin", tmp_bson ("{'buildinfo': 1}"), NULL, &reply, &error), error); ret = _parse_server_version (&reply); bson_destroy (&reply); mongoc_client_destroy (client); return ret; } server_version_t test_framework_str_to_version (const char *version_str) { char *str_copy; char *part; char *end; int i; server_version_t ret = 0; str_copy = bson_strdup (version_str); i = 0; part = strtok (str_copy, "."); while (part) { ret *= 1000; /* add 100 since release candidates have versions like "3.2.0.-49" */ ret += 100 + bson_ascii_strtoll (part, &end, 10); i++; ASSERT_CMPINT (i, <=, N_SERVER_VERSION_PARTS); part = strtok (NULL, "."); } /* pad out a short version like "3.0" */ for (; i < N_SERVER_VERSION_PARTS; i++) { ret *= 1000; ret += 100; } bson_free (str_copy); return ret; } /* self-tests for a test framework feature */ static void test_version_cmp (void) { server_version_t v2_6_12 = 102106112100; server_version_t v3_0_0 = 103100100100; server_version_t v3_0_1 = 103100101100; server_version_t v3_0_10 = 103100110100; server_version_t v3_2_0_rc1_pre = 103102100051; ASSERT (v2_6_12 == test_framework_str_to_version ("2.6.12")); ASSERT (v2_6_12 == _parse_server_version ( tmp_bson ("{'versionArray': [2, 6, 12, 0]}"))); ASSERT (v3_0_0 == test_framework_str_to_version ("3")); ASSERT (v3_0_0 == _parse_server_version ( tmp_bson ("{'versionArray': [3, 0, 0, 0]}"))); ASSERT (v3_0_1 == test_framework_str_to_version ("3.0.1")); ASSERT (v3_0_1 == _parse_server_version ( tmp_bson ("{'versionArray': [3, 0, 1, 0]}"))); ASSERT (v3_0_10 == test_framework_str_to_version ("3.0.10")); ASSERT (v3_0_10 == _parse_server_version ( tmp_bson ("{'versionArray': [3, 0, 10, 0]}"))); ASSERT (v3_2_0_rc1_pre == test_framework_str_to_version ("3.2.0.-49")); ASSERT (v3_2_0_rc1_pre == _parse_server_version ( tmp_bson ("{'versionArray': [3, 2, 0, -49]}"))); ASSERT (v3_2_0_rc1_pre > test_framework_str_to_version ("3.1.9")); ASSERT (v3_2_0_rc1_pre < test_framework_str_to_version ("3.2")); } int test_framework_skip_if_single (void) { return (test_framework_is_mongos () || test_framework_is_replset()); } int test_framework_skip_if_mongos (void) { return test_framework_is_mongos() ? 0 : 1; } int test_framework_skip_if_replset (void) { return test_framework_is_replset() ? 0 : 1; } int test_framework_skip_if_not_single (void) { return !test_framework_skip_if_single (); } int test_framework_skip_if_not_mongos (void) { return !test_framework_skip_if_mongos (); } int test_framework_skip_if_not_replset (void) { return !test_framework_skip_if_replset (); } int test_framework_skip_if_max_version_version_less_than_4 (void) { return test_framework_max_wire_version_at_least (4); } int main (int argc, char *argv[]) { TestSuite suite; int ret; mongoc_init (); bson_snprintf (MONGOC_TEST_UNIQUE, sizeof MONGOC_TEST_UNIQUE, "test_%u_%u", (unsigned)time (NULL), (unsigned)gettestpid ()); mongoc_log_set_handler (log_handler, NULL); #ifdef MONGOC_ENABLE_SSL test_framework_global_ssl_opts_init (); atexit (test_framework_global_ssl_opts_cleanup); #endif TestSuite_Init (&suite, "", argc, argv); TestSuite_Add (&suite, "/TestSuite/version_cmp", test_version_cmp); test_array_install (&suite); test_async_install (&suite); test_buffer_install (&suite); test_client_install (&suite); test_client_pool_install (&suite); test_write_command_install (&suite); test_bulk_install (&suite); test_cluster_install (&suite); test_collection_install (&suite); test_collection_find_install (&suite); test_cursor_install (&suite); test_database_install (&suite); test_exhaust_install (&suite); test_find_and_modify_install (&suite); test_gridfs_install (&suite); test_gridfs_file_page_install (&suite); test_list_install (&suite); test_log_install (&suite); test_matcher_install (&suite); test_queue_install (&suite); test_read_prefs_install (&suite); test_rpc_install (&suite); test_sasl_install (&suite); test_socket_install (&suite); test_topology_scanner_install (&suite); test_topology_reconcile_install (&suite); test_sdam_install (&suite); test_server_selection_install (&suite); test_server_selection_errors_install (&suite); test_set_install (&suite); test_stream_install (&suite); test_thread_install (&suite); test_topology_install (&suite); test_uri_install (&suite); test_usleep_install (&suite); test_version_install (&suite); test_write_concern_install (&suite); #ifdef MONGOC_ENABLE_SSL test_x509_install (&suite); test_stream_tls_install (&suite); test_stream_tls_error_install (&suite); #endif ret = TestSuite_Run (&suite); TestSuite_Destroy (&suite); mongoc_cleanup(); return ret; } libmongoc-1.3.1/tests/test-libmongoc.h000066400000000000000000000060321264720626300177370ustar00rootroot00000000000000/* * Copyright 2013 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef TEST_LIBMONGOC_H #define TEST_LIBMONGOC_H char *gen_collection_name (const char *prefix); void suppress_one_message (void); char *test_framework_getenv (const char *name); bool test_framework_getenv_bool (const char *name); int64_t test_framework_getenv_int64 (const char *name, int64_t default_value); char *test_framework_get_host (void); uint16_t test_framework_get_port (void); char *test_framework_get_admin_user (void); char *test_framework_get_admin_password (void); bool test_framework_get_ssl (void); char *test_framework_add_user_password (const char *uri_str, const char *user, const char *password); char *test_framework_add_user_password_from_env (const char *uri_str); char *test_framework_get_uri_str_no_auth (const char *database_name); char *test_framework_get_uri_str (void); char *test_framework_get_unix_domain_socket_uri_str (void); char *test_framework_get_unix_domain_socket_path (void); mongoc_uri_t *test_framework_get_uri (void); #ifdef MONGOC_ENABLE_SSL const mongoc_ssl_opt_t *test_framework_get_ssl_opts (void); #endif void test_framework_set_ssl_opts (mongoc_client_t *client); void test_framework_set_pool_ssl_opts (mongoc_client_pool_t *pool); mongoc_client_t *test_framework_client_new (void); mongoc_client_pool_t *test_framework_client_pool_new (void); bool test_framework_is_mongos (void); bool test_framework_is_replset (void); bool test_framework_server_is_secondary (mongoc_client_t *client, uint32_t server_id); bool test_framework_max_wire_version_at_least (int version); int test_framework_skip_if_max_version_version_less_than_4 (void); int test_framework_skip_if_mongos (void); int test_framework_skip_if_replset (void); int test_framework_skip_if_single (void); int test_framework_skip_if_windows (void); int test_framework_skip_if_not_mongos (void); int test_framework_skip_if_not_replset (void); int test_framework_skip_if_not_single (void); typedef struct _debug_stream_stats_t { mongoc_client_t *client; int n_destroyed; int n_failed; } debug_stream_stats_t; void test_framework_set_debug_stream (mongoc_client_t *client, debug_stream_stats_t *stats); typedef int64_t server_version_t; server_version_t test_framework_get_server_version (void); server_version_t test_framework_str_to_version (const char *version_str); #endif libmongoc-1.3.1/tests/test-load.c000066400000000000000000000053601264720626300167030ustar00rootroot00000000000000#include #include static void print_doc (const bson_t *b) { char *str; str = bson_as_json(b, NULL); MONGOC_DEBUG("%s", str); bson_free(str); } static void ping (mongoc_database_t *db, const bson_t *cmd) { mongoc_cursor_t *cursor; const bson_t *b; bson_error_t error; cursor = mongoc_database_command(db, MONGOC_QUERY_NONE, 0, 1, 0, cmd, NULL, NULL); while (mongoc_cursor_next(cursor, &b)) { BSON_ASSERT(b); print_doc(b); } if (mongoc_cursor_error(cursor, &error)) { MONGOC_WARNING("Cursor error: %s", error.message); } mongoc_cursor_destroy(cursor); } static void fetch (mongoc_collection_t *col, const bson_t *spec) { mongoc_cursor_t *cursor; const bson_t *b; bson_error_t error; cursor = mongoc_collection_find(col, MONGOC_QUERY_NONE, 0, 0, 0, spec, NULL, NULL); while (mongoc_cursor_next(cursor, &b)) { BSON_ASSERT(b); print_doc(b); } if (mongoc_cursor_error(cursor, &error)) { MONGOC_WARNING("Cursor error: %s", error.message); } mongoc_cursor_destroy(cursor); } static void test_load (mongoc_client_t *client, unsigned iterations) { mongoc_collection_t *col; mongoc_database_t *db; bson_error_t error; unsigned i; bson_t b; bson_t q; bson_init(&b); bson_append_int32(&b, "ping", 4, 1); bson_init(&q); db = mongoc_client_get_database(client, "admin"); col = mongoc_client_get_collection(client, "test", "test"); for (i = 0; i < iterations; i++) { ping(db, &b); fetch(col, &q); } if (!mongoc_collection_drop(col, &error)) { MONGOC_WARNING("Failed to drop collection: %s", error.message); } mongoc_database_destroy(db); db = mongoc_client_get_database(client, "test"); if (!mongoc_database_drop(db, &error)) { MONGOC_WARNING("Failed to drop database: %s", error.message); } mongoc_database_destroy(db); mongoc_collection_destroy(col); bson_destroy(&b); } int main (int argc, char *argv[]) { mongoc_client_pool_t *pool; mongoc_client_t *client; mongoc_uri_t *uri; unsigned count = 10000000; mongoc_init(); if (argc > 1) { if (!(uri = mongoc_uri_new(argv[1]))) { fprintf(stderr, "Failed to parse uri: %s\n", argv[1]); return 1; } } else { uri = mongoc_uri_new("mongodb://127.0.0.1:27017/?sockettimeoutms=500"); } if (argc > 2) { count = BSON_MAX(atoi(argv[2]), 1); } pool = mongoc_client_pool_new(uri); client = mongoc_client_pool_pop(pool); test_load(client, count); mongoc_client_pool_push(pool, client); mongoc_uri_destroy(uri); mongoc_client_pool_destroy(pool); mongoc_cleanup(); return 0; } libmongoc-1.3.1/tests/test-mongoc-array.c000066400000000000000000000014351264720626300203610ustar00rootroot00000000000000#include "mongoc-array-private.h" #include "TestSuite.h" static void test_array (void) { mongoc_array_t ar; int i; int v; _mongoc_array_init(&ar, sizeof i); assert(ar.element_size == sizeof i); assert(ar.len == 0); assert(ar.allocated); assert(ar.data); for (i = 0; i < 100; i++) { _mongoc_array_append_val(&ar, i); } for (i = 0; i < 100; i++) { v = _mongoc_array_index(&ar, int, i); assert(v == i); } assert(ar.len == 100); assert(ar.allocated >= (100 * sizeof i)); _mongoc_array_clear(&ar); assert(ar.len == 0); assert(ar.allocated); assert(ar.data); assert(ar.element_size); _mongoc_array_destroy(&ar); } void test_array_install (TestSuite *suite) { TestSuite_Add (suite, "/Array/Basic", test_array); } libmongoc-1.3.1/tests/test-mongoc-async.c000066400000000000000000000111101264720626300203470ustar00rootroot00000000000000#include #include "mongoc-async-private.h" #include "mongoc-async-cmd-private.h" #include "mongoc-tests.h" #include "TestSuite.h" #include "mock_server/mock-server.h" #include "mongoc-errno-private.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "async-test" #define TIMEOUT 10000 /* milliseconds */ #define NSERVERS 10 #define TRUST_DIR "tests/trust_dir" #define CAFILE TRUST_DIR "/verify/mongo_root.pem" #define PEMFILE_NOPASS TRUST_DIR "/keys/mongodb.com.pem" struct result { int32_t max_wire_version; bool finished; }; static void test_ismaster_helper (mongoc_async_cmd_result_t result, const bson_t *bson, int64_t rtt_msec, void *data, bson_error_t *error) { struct result *r = (struct result *)data; bson_iter_t iter; if (result != MONGOC_ASYNC_CMD_SUCCESS) { fprintf(stderr, "error: %s\n", error->message); } assert(result == MONGOC_ASYNC_CMD_SUCCESS); assert (bson_iter_init_find (&iter, bson, "maxWireVersion")); assert (BSON_ITER_HOLDS_INT32 (&iter)); r->max_wire_version = bson_iter_int32 (&iter); r->finished = true; } static void test_ismaster_impl (bool with_ssl) { mock_server_t *servers[NSERVERS]; mongoc_async_t *async; mongoc_stream_t *sock_streams[NSERVERS]; mongoc_socket_t *conn_sock; mongoc_async_cmd_setup_t setup = NULL; void *setup_ctx = NULL; struct sockaddr_in server_addr = { 0 }; uint16_t ports[NSERVERS]; struct result results[NSERVERS]; int r; int i; int errcode; bson_t q = BSON_INITIALIZER; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; #endif assert(bson_append_int32 (&q, "isMaster", 8, 1)); for (i = 0; i < NSERVERS; i++) { /* use max wire versions just to distinguish among responses */ servers[i] = mock_server_with_autoismaster (i); #ifdef MONGOC_ENABLE_SSL if (with_ssl) { sopt.pem_file = PEMFILE_NOPASS; sopt.ca_file = CAFILE; mock_server_set_ssl_opts (servers[i], &sopt); } #endif ports[i] = mock_server_run (servers[i]); } async = mongoc_async_new (); for (i = 0; i < NSERVERS; i++) { conn_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (conn_sock); server_addr.sin_family = AF_INET; server_addr.sin_port = htons (ports[i]); server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); r = mongoc_socket_connect (conn_sock, (struct sockaddr *)&server_addr, sizeof (server_addr), 0); errcode = mongoc_socket_errno (conn_sock); if (!(r == 0 || MONGOC_ERRNO_IS_AGAIN (errcode))) { fprintf (stderr, "mongoc_socket_connect unexpected return: " "%d (errno: %d)\n", r, errcode); fflush (stderr); abort (); } sock_streams[i] = mongoc_stream_socket_new (conn_sock); #ifdef MONGOC_ENABLE_SSL if (with_ssl) { copt.ca_file = CAFILE; copt.weak_cert_validation = 1; sock_streams[i] = mongoc_stream_tls_new (sock_streams[i], &copt, 1); setup = mongoc_async_cmd_tls_setup; setup_ctx = (void *)"127.0.0.1"; } #endif results[i].finished = false; mongoc_async_cmd (async, sock_streams[i], setup, setup_ctx, "admin", &q, &test_ismaster_helper, (void *)&results[i], TIMEOUT); } while (mongoc_async_run (async, TIMEOUT)) { } for (i = 0; i < NSERVERS; i++) { if (!results[i].finished) { fprintf (stderr, "command %d not finished\n", i); abort (); } /* received the maxWireVersion configured above */ ASSERT_CMPINT (i, ==, results[i].max_wire_version); } mongoc_async_destroy (async); bson_destroy (&q); for (i = 0; i < NSERVERS; i++) { mock_server_destroy (servers[i]); mongoc_stream_destroy (sock_streams[i]); } } static void test_ismaster (void) { test_ismaster_impl(false); } #ifdef MONGOC_ENABLE_SSL static void test_ismaster_ssl (void) { test_ismaster_impl(true); } #endif void test_async_install (TestSuite *suite) { TestSuite_Add (suite, "/Async/ismaster", test_ismaster); #ifdef MONGOC_ENABLE_SSL TestSuite_Add (suite, "/Async/ismaster_ssl", test_ismaster_ssl); #endif } libmongoc-1.3.1/tests/test-mongoc-buffer.c000066400000000000000000000016721264720626300205170ustar00rootroot00000000000000#include #include #include #include "TestSuite.h" static void test_mongoc_buffer_basic (void) { mongoc_stream_t *stream; mongoc_buffer_t buf; bson_error_t error = { 0 }; uint8_t *data = (uint8_t *)bson_malloc0(1024); ssize_t r; stream = mongoc_stream_file_new_for_path (BINARY_DIR"/reply1.dat", O_RDONLY, 0); ASSERT(stream); _mongoc_buffer_init(&buf, data, 1024, NULL, NULL); r = _mongoc_buffer_fill(&buf, stream, 537, 0, &error); ASSERT_CMPINT((int)r, ==, -1); r = _mongoc_buffer_fill(&buf, stream, 536, 0, &error); ASSERT_CMPINT((int)r, ==, 536); ASSERT(buf.len == 536); _mongoc_buffer_destroy(&buf); _mongoc_buffer_destroy(&buf); _mongoc_buffer_destroy(&buf); _mongoc_buffer_destroy(&buf); mongoc_stream_destroy(stream); } void test_buffer_install (TestSuite *suite) { TestSuite_Add (suite, "/Buffer/Basic", test_mongoc_buffer_basic); } libmongoc-1.3.1/tests/test-mongoc-client-pool.c000066400000000000000000000112711264720626300214670ustar00rootroot00000000000000#include #include "mongoc-client-pool-private.h" #include "mongoc-array-private.h" #include "TestSuite.h" #include "test-libmongoc.h" static void test_mongoc_client_pool_basic (void) { mongoc_client_pool_t *pool; mongoc_client_t *client; mongoc_uri_t *uri; uri = mongoc_uri_new("mongodb://127.0.0.1?maxpoolsize=1&minpoolsize=1"); pool = mongoc_client_pool_new(uri); client = mongoc_client_pool_pop(pool); assert(client); mongoc_client_pool_push(pool, client); mongoc_uri_destroy(uri); mongoc_client_pool_destroy(pool); } static void test_mongoc_client_pool_try_pop (void) { mongoc_client_pool_t *pool; mongoc_client_t *client; mongoc_uri_t *uri; uri = mongoc_uri_new("mongodb://127.0.0.1?maxpoolsize=1&minpoolsize=1"); pool = mongoc_client_pool_new(uri); client = mongoc_client_pool_pop(pool); assert(client); assert(!mongoc_client_pool_try_pop(pool)); mongoc_client_pool_push(pool, client); mongoc_uri_destroy(uri); mongoc_client_pool_destroy(pool); } static void test_mongoc_client_pool_min_size_dispose (void) { mongoc_client_pool_t *pool; mongoc_client_t *client; mongoc_uri_t *uri; mongoc_array_t conns; int i; _mongoc_array_init (&conns, sizeof client); uri = mongoc_uri_new ("mongodb://127.0.0.1?maxpoolsize=10&minpoolsize=3"); pool = mongoc_client_pool_new (uri); for (i = 0; i < 10; i++) { client = mongoc_client_pool_pop (pool); assert (client); _mongoc_array_append_val (&conns, client); assert (mongoc_client_pool_get_size (pool) == i + 1); } for (i = 0; i < 10; i++) { client = _mongoc_array_index (&conns, mongoc_client_t *, i); assert (client); mongoc_client_pool_push (pool, client); } assert (mongoc_client_pool_get_size (pool) == 3); _mongoc_array_clear (&conns); _mongoc_array_destroy (&conns); mongoc_uri_destroy (uri); mongoc_client_pool_destroy (pool); } static void test_mongoc_client_pool_set_max_size (void) { mongoc_client_pool_t *pool; mongoc_client_t *client; mongoc_uri_t *uri; mongoc_array_t conns; int i; _mongoc_array_init (&conns, sizeof client); uri = mongoc_uri_new ("mongodb://127.0.0.1?maxpoolsize=10&minpoolsize=3"); pool = mongoc_client_pool_new (uri); for (i = 0; i < 5; i++) { client = mongoc_client_pool_pop (pool); assert (client); _mongoc_array_append_val (&conns, client); assert (mongoc_client_pool_get_size (pool) == i + 1); } mongoc_client_pool_max_size(pool,3); assert(mongoc_client_pool_try_pop(pool) == NULL); for (i = 0; i < 5; i++) { client = _mongoc_array_index (&conns, mongoc_client_t *, i); assert (client); mongoc_client_pool_push (pool, client); } _mongoc_array_clear (&conns); _mongoc_array_destroy (&conns); mongoc_uri_destroy (uri); mongoc_client_pool_destroy (pool); } static void test_mongoc_client_pool_set_min_size (void) { mongoc_client_pool_t *pool; mongoc_client_t *client; mongoc_uri_t *uri; mongoc_array_t conns; int i; _mongoc_array_init (&conns, sizeof client); uri = mongoc_uri_new ("mongodb://127.0.0.1?maxpoolsize=10&minpoolsize=3"); pool = mongoc_client_pool_new (uri); for (i = 0; i < 10; i++) { client = mongoc_client_pool_pop (pool); assert (client); _mongoc_array_append_val (&conns, client); assert (mongoc_client_pool_get_size (pool) == i + 1); } mongoc_client_pool_min_size(pool,7); for (i = 0; i < 10; i++) { client = _mongoc_array_index (&conns, mongoc_client_t *, i); assert (client); mongoc_client_pool_push (pool, client); } assert (mongoc_client_pool_get_size (pool) == 7); _mongoc_array_clear (&conns); _mongoc_array_destroy (&conns); mongoc_uri_destroy (uri); mongoc_client_pool_destroy (pool); } #ifndef MONGOC_ENABLE_SSL static void test_mongoc_client_pool_ssl_disabled (void) { mongoc_uri_t *uri = mongoc_uri_new ("mongodb://host/?ssl=true"); ASSERT (uri); suppress_one_message (); ASSERT (NULL == mongoc_client_pool_new (uri)); mongoc_uri_destroy (uri); } #endif void test_client_pool_install (TestSuite *suite) { TestSuite_Add (suite, "/ClientPool/basic", test_mongoc_client_pool_basic); TestSuite_Add (suite, "/ClientPool/try_pop", test_mongoc_client_pool_try_pop); TestSuite_Add (suite, "/ClientPool/min_size_dispose", test_mongoc_client_pool_min_size_dispose); TestSuite_Add (suite, "/ClientPool/set_max_size", test_mongoc_client_pool_set_max_size); TestSuite_Add (suite, "/ClientPool/set_min_size", test_mongoc_client_pool_set_min_size); #ifndef MONGOC_ENABLE_SSL TestSuite_Add (suite, "/ClientPool/ssl_disabled", test_mongoc_client_pool_ssl_disabled); #endif } libmongoc-1.3.1/tests/test-mongoc-client.c000066400000000000000000001021401264720626300205140ustar00rootroot00000000000000#include #include #include "mongoc-client-private.h" #include "mongoc-cursor-private.h" #include "mongoc-uri-private.h" #include "mongoc-util-private.h" #include "TestSuite.h" #include "test-conveniences.h" #include "test-libmongoc.h" #include "mock_server/future.h" #include "mock_server/future-functions.h" #include "mock_server/mock-server.h" #include "mongoc-tests.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "client-test" static char * gen_test_user (void) { return bson_strdup_printf ("testuser_%u_%u", (unsigned)time(NULL), (unsigned)gettestpid()); } static char * gen_good_uri (const char *username, const char *dbname) { char *host = test_framework_get_host (); uint16_t port = test_framework_get_port (); char *uri = bson_strdup_printf ("mongodb://%s:testpass@%s:%hu/%s", username, host, port, dbname); bson_free (host); return uri; } static void test_mongoc_client_authenticate (void *context) { mongoc_client_t *admin_client; char *username; char *uri; bson_t roles; mongoc_database_t *database; char *uri_str_no_auth; char *uri_str_auth; mongoc_collection_t *collection; mongoc_client_t *auth_client; mongoc_cursor_t *cursor; const bson_t *doc; bson_error_t error; bool r; bson_t q; /* * Log in as admin. */ admin_client = test_framework_client_new (); /* * Add a user to the test database. */ username = gen_test_user (); uri = gen_good_uri (username, "test"); database = mongoc_client_get_database (admin_client, "test"); mongoc_database_remove_user (database, username, &error); bson_init (&roles); BCON_APPEND (&roles, "0", "{", "role", "read", "db", "test", "}"); ASSERT_OR_PRINT (mongoc_database_add_user(database, username, "testpass", &roles, NULL, &error), error); mongoc_database_destroy(database); /* * Try authenticating with that user. */ bson_init(&q); uri_str_no_auth = test_framework_get_uri_str_no_auth ("test"); uri_str_auth = test_framework_add_user_password (uri_str_no_auth, username, "testpass"); auth_client = mongoc_client_new (uri_str_auth); test_framework_set_ssl_opts (auth_client); collection = mongoc_client_get_collection (auth_client, "test", "test"); cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 1, 0, &q, NULL, NULL); r = mongoc_cursor_next(cursor, &doc); if (!r) { r = mongoc_cursor_error(cursor, &error); if (r) { fprintf (stderr, "Authentication failure: \"%s\"", error.message); } assert(!r); } /* * Remove all test users. */ database = mongoc_client_get_database (admin_client, "test"); r = mongoc_database_remove_all_users (database, &error); assert (r); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); bson_free (uri_str_no_auth); bson_free (uri_str_auth); mongoc_client_destroy (auth_client); bson_destroy (&roles); bson_free (uri); bson_free (username); mongoc_database_destroy (database); mongoc_client_destroy (admin_client); } static int should_run_auth_tests (void) { char *user; #ifndef MONGOC_ENABLE_SSL if (test_framework_max_wire_version_at_least (3)) { /* requires SSL for SCRAM implementation, can't test auth */ return 0; } #endif /* run auth tests if the MONGOC_TEST_USER env var is set */ user = test_framework_get_admin_user (); bson_free (user); return user ? 1 : 0; } static void test_mongoc_client_authenticate_failure (void *context) { mongoc_collection_t *collection; mongoc_cursor_t *cursor; mongoc_client_t *client; const bson_t *doc; bson_error_t error; bool r; bson_t q; bson_t empty = BSON_INITIALIZER; char *host = test_framework_get_host (); char *uri_str_no_auth = test_framework_get_uri_str_no_auth (NULL); char *bad_uri_str = test_framework_add_user_password (uri_str_no_auth, "baduser", "badpass"); /* * Try authenticating with bad user. */ bson_init(&q); client = mongoc_client_new (bad_uri_str); test_framework_set_ssl_opts (client); collection = mongoc_client_get_collection(client, "test", "test"); suppress_one_message (); cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 1, 0, &q, NULL, NULL); suppress_one_message (); r = mongoc_cursor_next(cursor, &doc); assert(!r); r = mongoc_cursor_error(cursor, &error); assert(r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_CLIENT); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_CLIENT_AUTHENTICATE); mongoc_cursor_destroy(cursor); /* * Try various commands while in the failed state to ensure we get the * same sort of errors. */ suppress_one_message (); suppress_one_message (); suppress_one_message (); r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, &empty, NULL, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_CLIENT); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_CLIENT_AUTHENTICATE); /* * Try various commands while in the failed state to ensure we get the * same sort of errors. */ suppress_one_message (); suppress_one_message (); suppress_one_message (); r = mongoc_collection_update (collection, MONGOC_UPDATE_NONE, &q, &empty, NULL, &error); assert (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_CLIENT); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_CLIENT_AUTHENTICATE); bson_free (host); bson_free (uri_str_no_auth); bson_free (bad_uri_str); mongoc_collection_destroy(collection); mongoc_client_destroy(client); } static void test_mongoc_client_authenticate_timeout (void *context) { mock_server_t *server; mongoc_uri_t *uri; mongoc_client_t *client; bson_t reply; bson_error_t error; future_t *future; request_t *request; server = mock_server_with_autoismaster (3); mock_server_run (server); uri = mongoc_uri_copy (mock_server_get_uri (server)); mongoc_uri_set_username (uri, "user"); mongoc_uri_set_password (uri, "password"); mongoc_uri_set_option_as_int32 (uri, "socketTimeoutMS", 10); client = mongoc_client_new_from_uri (uri); future = future_client_command_simple (client, "test", tmp_bson ("{'ping': 1}"), NULL, &reply, &error); request = mock_server_receives_command (server, "admin", MONGOC_QUERY_SLAVE_OK, NULL); ASSERT (request); ASSERT_CMPSTR (request->command_name, "saslStart"); /* don't reply */ assert (!future_get_bool (future)); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_CLIENT); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_CLIENT_AUTHENTICATE); ASSERT_STARTSWITH ( error.message, "Failed to send \"saslStart\" command with database \"admin\""); ASSERT_CONTAINS (error.message, "within 10 milliseconds"); bson_destroy (&reply); future_destroy (future); request_destroy (request); mongoc_uri_destroy (uri); mongoc_client_destroy(client); mock_server_destroy (server); } #ifdef TODO_CDRIVER_689 static void test_wire_version (void) { mongoc_collection_t *collection; mongoc_cursor_t *cursor; mongoc_client_t *client; mock_server_t *server; const bson_t *doc; bson_error_t error; bool r; bson_t q = BSON_INITIALIZER; server = mock_server_new (); mock_server_auto_ismaster (server, "{'ok': 1.0," " 'ismaster': true," " 'minWireVersion': 10," " 'maxWireVersion': 11}"); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "test", "test"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 1, 0, &q, NULL, NULL); r = mongoc_cursor_next (cursor, &doc); assert (!r); r = mongoc_cursor_error (cursor, &error); assert (r); assert (error.domain == MONGOC_ERROR_PROTOCOL); assert (error.code == MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } #endif static void test_mongoc_client_command (void) { mongoc_client_t *client; mongoc_cursor_t *cursor; const bson_t *doc; bool r; bson_t cmd = BSON_INITIALIZER; client = test_framework_client_new (); assert (client); bson_append_int32 (&cmd, "ping", 4, 1); cursor = mongoc_client_command (client, "admin", MONGOC_QUERY_NONE, 0, 1, 0, &cmd, NULL, NULL); r = mongoc_cursor_next (cursor, &doc); assert (r); assert (doc); r = mongoc_cursor_next (cursor, &doc); assert (!r); assert (!doc); mongoc_cursor_destroy (cursor); mongoc_client_destroy (client); bson_destroy (&cmd); } static void test_mongoc_client_command_secondary (void) { mongoc_client_t *client; mongoc_cursor_t *cursor; mongoc_read_prefs_t *read_prefs; bson_t cmd = BSON_INITIALIZER; const bson_t *reply; client = test_framework_client_new (); assert (client); BSON_APPEND_INT32 (&cmd, "invalid_command_here", 1); read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); suppress_one_message (); cursor = mongoc_client_command (client, "admin", MONGOC_QUERY_NONE, 0, 1, 0, &cmd, NULL, read_prefs); mongoc_cursor_next (cursor, &reply); if (test_framework_is_replset ()) { assert (test_framework_server_is_secondary (client, cursor->hint)); } mongoc_read_prefs_destroy (read_prefs); mongoc_cursor_destroy (cursor); mongoc_client_destroy (client); bson_destroy (&cmd); } static void test_command_not_found (void) { mongoc_client_t *client; const bson_t *doc; bson_error_t error; mongoc_cursor_t *cursor; client = test_framework_client_new (); cursor = mongoc_client_command (client, "test", MONGOC_QUERY_NONE, 0, 0, 0, tmp_bson ("{'foo': 1}"), NULL, NULL); ASSERT (!mongoc_cursor_next (cursor, &doc)); ASSERT (mongoc_cursor_error (cursor, &error)); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_QUERY); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND); mongoc_cursor_destroy (cursor); mongoc_client_destroy (client); } static void test_command_not_found_simple (void) { mongoc_client_t *client; bson_t reply; bson_error_t error; client = test_framework_client_new (); ASSERT (!mongoc_client_command_simple (client, "test", tmp_bson ("{'foo': 1}"), NULL, &reply, &error)); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_QUERY); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND); bson_destroy (&reply); mongoc_client_destroy (client); } static void test_unavailable_seeds (void) { mock_server_t *servers[2]; char **uri_strs; char **uri_str; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_t query = BSON_INITIALIZER; const bson_t *doc; bson_error_t error; int i; for (i = 0; i < 2; i++) { servers[i] = mock_server_down (); /* hangs up on all requests */ mock_server_run (servers[i]); } uri_str = uri_strs = bson_malloc0 (7 * sizeof (char *)); *(uri_str++) = bson_strdup_printf ( "mongodb://%s", mock_server_get_host_and_port (servers[0])); *(uri_str++) = bson_strdup_printf ( "mongodb://%s,%s", mock_server_get_host_and_port (servers[0]), mock_server_get_host_and_port (servers[1])); *(uri_str++) = bson_strdup_printf ( "mongodb://%s,%s/?replicaSet=rs", mock_server_get_host_and_port (servers[0]), mock_server_get_host_and_port (servers[1])); *(uri_str++) = bson_strdup_printf ( "mongodb://u:p@%s", mock_server_get_host_and_port (servers[0])); *(uri_str++) = bson_strdup_printf ( "mongodb://u:p@%s,%s", mock_server_get_host_and_port (servers[0]), mock_server_get_host_and_port (servers[1])); *(uri_str++) = bson_strdup_printf ( "mongodb://u:p@%s,%s/?replicaSet=rs", mock_server_get_host_and_port (servers[0]), mock_server_get_host_and_port (servers[1])); for (i = 0; i < (sizeof(uri_strs) / sizeof(const char *)); i++) { client = mongoc_client_new (uri_strs[i]); assert (client); collection = mongoc_client_get_collection (client, "test", "test"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, NULL); assert (! mongoc_cursor_next (cursor, &doc)); assert (mongoc_cursor_error (cursor, &error)); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_SERVER_SELECTION); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_SERVER_SELECTION_FAILURE); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } for (i = 0; i < 2; i++) { mock_server_destroy (servers[i]); } bson_strfreev (uri_strs); } typedef enum { NO_CONNECT, CONNECT, RECONNECT } connection_option_t; static bool responder (request_t *request, void *data) { if (!strcmp (request->command_name, "foo")) { mock_server_replies_simple (request, "{'ok': 1}"); request_destroy (request); return true; } return false; } /* mongoc_set_for_each callback */ static bool host_equals (void *item, void *ctx) { mongoc_server_description_t *sd; const char *host_and_port; sd = (mongoc_server_description_t *) item; host_and_port = (const char *) ctx; return !strcasecmp (sd->host.host_and_port, host_and_port); } /* CDRIVER-721 catch errors in _mongoc_cluster_destroy */ static void test_seed_list (bool rs, connection_option_t connection_option, bool pooled) { mock_server_t *server; mock_server_t *down_servers[3]; int i; char *uri_str; mongoc_uri_t *uri; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; mongoc_topology_t *topology; mongoc_topology_description_t *td; mongoc_read_prefs_t *primary_pref; uint32_t discovered_nodes_len; int64_t start; int64_t duration_usec; bson_t reply; bson_error_t error; uint32_t id; server = mock_server_new (); mock_server_run (server); for (i = 0; i < 3; i++) { down_servers[i] = mock_server_down (); mock_server_run (down_servers[i]); } uri_str = bson_strdup_printf ( "mongodb://%s,%s,%s,%s", mock_server_get_host_and_port (server), mock_server_get_host_and_port (down_servers[0]), mock_server_get_host_and_port (down_servers[1]), mock_server_get_host_and_port (down_servers[2])); uri = mongoc_uri_new (uri_str); assert (uri); if (pooled) { /* must be >= minHeartbeatFrequencyMS=500 or the "reconnect" * case won't have time to succeed */ mongoc_uri_set_option_as_int32 (uri, "serverSelectionTimeoutMS", 1000); } if (rs) { mock_server_auto_ismaster (server, "{'ok': 1," " 'ismaster': true," " 'setName': 'rs'," " 'hosts': ['%s']}", mock_server_get_host_and_port (server)); mongoc_uri_set_option_as_utf8 (uri, "replicaSet", "rs"); } else { mock_server_auto_ismaster (server, "{'ok': 1," " 'ismaster': true," " 'msg': 'isdbgrid'}"); } /* auto-respond to "foo" command */ mock_server_autoresponds (server, responder, NULL, NULL); if (pooled) { pool = mongoc_client_pool_new (uri); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new_from_uri (uri); } topology = client->topology; td = &topology->description; /* a mongos load-balanced connection never removes down nodes */ discovered_nodes_len = rs ? 1 : 4; primary_pref = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); if (connection_option == CONNECT || connection_option == RECONNECT) { start = bson_get_monotonic_time (); /* only localhost:port responds to initial discovery. the other seeds are * discarded from replica set topology, but remain for sharded. */ ASSERT_OR_PRINT (mongoc_client_command_simple ( client, "test", tmp_bson("{'foo': 1}"), primary_pref, &reply, &error), error); /* discovery should be quick despite down servers, say < 100ms */ duration_usec = bson_get_monotonic_time () - start; ASSERT_CMPINT ((int) (duration_usec / 1000), <, 100); bson_destroy (&reply); ASSERT_CMPINT (discovered_nodes_len, ==, (int) td->servers->items_len); if (rs) { ASSERT_CMPINT (td->type, ==, MONGOC_TOPOLOGY_RS_WITH_PRIMARY); } else { ASSERT_CMPINT (td->type, ==, MONGOC_TOPOLOGY_SHARDED); } if (pooled) { /* nodes created on demand when we use servers for actual operations */ ASSERT_CMPINT ((int) client->cluster.nodes->items_len, ==, 1); } } if (connection_option == RECONNECT) { id = mongoc_set_find_id (td->servers, host_equals, (void *) mock_server_get_host_and_port (server)); ASSERT_CMPINT (id, !=, 0); mongoc_topology_invalidate_server (topology, id); if (rs) { ASSERT_CMPINT (td->type, ==, MONGOC_TOPOLOGY_RS_NO_PRIMARY); } else { ASSERT_CMPINT (td->type, ==, MONGOC_TOPOLOGY_SHARDED); } ASSERT_OR_PRINT (mongoc_client_command_simple ( client, "test", tmp_bson("{'foo': 1}"), primary_pref, &reply, &error), error); /* client waited for min heartbeat to pass before reconnecting, then * reconnected quickly despite down servers, say < 100ms later */ duration_usec = bson_get_monotonic_time () - start; ASSERT_CMPINT ((int) (duration_usec / 1000), <, MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS + 100); bson_destroy (&reply); ASSERT_CMPINT (discovered_nodes_len, ==, (int) td->servers->items_len); if (pooled) { ASSERT_CMPINT ((int) client->cluster.nodes->items_len, ==, 1); } } /* testing for crashes like CDRIVER-721 */ if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } mongoc_read_prefs_destroy (primary_pref); mongoc_uri_destroy (uri); bson_free (uri_str); for (i = 0; i < 3; i++) { mock_server_destroy (down_servers[i]); } mock_server_destroy (server); } static void test_rs_seeds_no_connect_single (void) { test_seed_list (true, NO_CONNECT, false); } static void test_rs_seeds_no_connect_pooled (void) { test_seed_list (true, NO_CONNECT, true); } static void test_rs_seeds_connect_single (void) { test_seed_list (true, CONNECT, false); } static void test_rs_seeds_connect_pooled (void) { test_seed_list (true, CONNECT, true); } static void test_rs_seeds_reconnect_single (void) { test_seed_list (true, RECONNECT, false); } static void test_rs_seeds_reconnect_pooled (void) { test_seed_list (true, RECONNECT, true); } static void test_mongos_seeds_no_connect_single (void) { test_seed_list (false, NO_CONNECT, false); } static void test_mongos_seeds_no_connect_pooled (void) { test_seed_list (false, NO_CONNECT, true); } static void test_mongos_seeds_connect_single (void) { test_seed_list (false, CONNECT, false); } static void test_mongos_seeds_connect_pooled (void) { test_seed_list (false, CONNECT, true); } static void test_mongos_seeds_reconnect_single (void) { test_seed_list (false, RECONNECT, false); } static void test_mongos_seeds_reconnect_pooled (void) { test_seed_list (false, RECONNECT, true); } static void test_recovering (void) { mock_server_t *server; mongoc_uri_t *uri; mongoc_client_t *client; mongoc_read_mode_t read_mode; mongoc_read_prefs_t *prefs; bson_error_t error; server = mock_server_new (); mock_server_run (server); /* server is "recovering": not master, not secondary */ mock_server_auto_ismaster (server, "{'ok': 1," " 'ismaster': false," " 'secondary': false," " 'setName': 'rs'," " 'hosts': ['%s']}", mock_server_get_host_and_port (server)); uri = mongoc_uri_copy (mock_server_get_uri (server)); mongoc_uri_set_option_as_utf8 (uri, "replicaSet", "rs"); client = mongoc_client_new_from_uri (uri); prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); /* recovering member matches no read mode */ for (read_mode = MONGOC_READ_PRIMARY; read_mode <= MONGOC_READ_NEAREST; read_mode++) { mongoc_read_prefs_set_mode (prefs, read_mode); assert (!mongoc_topology_select (client->topology, MONGOC_SS_READ, prefs, 15, &error)); } mongoc_read_prefs_destroy (prefs); mongoc_client_destroy (client); mongoc_uri_destroy (uri); mock_server_destroy (server); } static void test_server_status (void) { mongoc_client_t *client; bson_error_t error; bson_iter_t iter; bson_t reply; client = test_framework_client_new (); assert (client); ASSERT_OR_PRINT (mongoc_client_get_server_status (client, NULL, &reply, &error), error); assert (bson_iter_init_find (&iter, &reply, "host")); assert (bson_iter_init_find (&iter, &reply, "version")); assert (bson_iter_init_find (&iter, &reply, "ok")); bson_destroy (&reply); mongoc_client_destroy (client); } static void test_get_database_names (void) { mock_server_t *server = mock_server_with_autoismaster (0); mongoc_client_t *client; bson_error_t error; future_t *future; request_t *request; char **names; mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); future = future_client_get_database_names (client, &error); request = mock_server_receives_command (server, "admin", MONGOC_QUERY_SLAVE_OK, "{'listDatabases': 1}"); mock_server_replies ( request, 0, 0, 0, 1, "{'ok': 1.0, 'databases': [{'name': 'a'}, {'name': 'b'}]}"); names = future_get_char_ptr_ptr (future); assert (!strcmp(names[0], "a")); assert (!strcmp(names[1], "b")); assert (NULL == names[2]); bson_strfreev (names); request_destroy (request); future_destroy (future); future = future_client_get_database_names (client, &error); request = mock_server_receives_command (server, "admin", MONGOC_QUERY_SLAVE_OK, "{'listDatabases': 1}"); mock_server_replies ( request, 0, 0, 0, 1, "{'ok': 0.0, 'code': 17, 'errmsg': 'err'}"); names = future_get_char_ptr_ptr (future); assert (!names); ASSERT_CMPINT (MONGOC_ERROR_QUERY, ==, error.domain); ASSERT_CMPSTR ("err", error.message); request_destroy (request); future_destroy (future); mongoc_client_destroy (client); mock_server_destroy (server); } static void test_mongoc_client_ipv6 (void) { mongoc_client_t *client; bson_error_t error; bson_iter_t iter; bson_t reply; client = mongoc_client_new ("mongodb://[::1]/"); assert (client); ASSERT_OR_PRINT (mongoc_client_get_server_status (client, NULL, &reply, &error), error); assert (bson_iter_init_find (&iter, &reply, "host")); assert (bson_iter_init_find (&iter, &reply, "version")); assert (bson_iter_init_find (&iter, &reply, "ok")); bson_destroy (&reply); mongoc_client_destroy (client); } static void test_mongoc_client_unix_domain_socket (void *context) { mongoc_client_t *client; bson_error_t error; char *uri_str; bson_iter_t iter; bson_t reply; uri_str = test_framework_get_unix_domain_socket_uri_str (); client = mongoc_client_new (uri_str); test_framework_set_ssl_opts (client); assert (client); ASSERT_OR_PRINT (mongoc_client_get_server_status (client, NULL, &reply, &error), error); assert (bson_iter_init_find (&iter, &reply, "host")); assert (bson_iter_init_find (&iter, &reply, "version")); assert (bson_iter_init_find (&iter, &reply, "ok")); bson_destroy (&reply); mongoc_client_destroy (client); } static void test_mongoc_client_mismatched_me (void) { mock_server_t *server; mongoc_uri_t *uri; mongoc_client_t *client; mongoc_read_prefs_t *prefs; bson_error_t error; future_t *future; request_t *request; char *reply; server = mock_server_new (); mock_server_run (server); uri = mongoc_uri_copy (mock_server_get_uri (server)); mongoc_uri_set_option_as_utf8 (uri, "replicaSet", "rs"); client = mongoc_client_new_from_uri (uri); prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); /* any operation should fail with server selection error */ future = future_client_command_simple (client, "admin", tmp_bson ("{'ping': 1}"), prefs, NULL, &error); request = mock_server_receives_ismaster (server); reply = bson_strdup_printf ( "{'ok': 1," " 'setName': 'rs'," " 'ismaster': false," " 'secondary': true," " 'me': 'foo.com'," /* mismatched "me" field */ " 'hosts': ['%s']}", mock_server_get_host_and_port (server)); mock_server_replies_simple (request, reply); assert (!future_get_bool (future)); ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "No suitable servers"); bson_free (reply); request_destroy (request); future_destroy (future); mongoc_read_prefs_destroy (prefs); mongoc_client_destroy (client); mongoc_uri_destroy (uri); mock_server_destroy (server); } #ifdef MONGOC_ENABLE_SSL static void _test_mongoc_client_ssl_opts (bool pooled) { char *host; uint16_t port; char *uri_str; char *uri_str_auth; char *uri_str_auth_ssl; mongoc_uri_t *uri; const mongoc_ssl_opt_t *ssl_opts; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; bool ret; bson_error_t error; int add_ssl_to_uri; host = test_framework_get_host (); port = test_framework_get_port (); uri_str = bson_strdup_printf ( "mongodb://%s:%d/?serverSelectionTimeoutMS=1000", host, port); uri_str_auth = test_framework_add_user_password_from_env (uri_str); uri_str_auth_ssl = bson_strdup_printf ("%s&ssl=true", uri_str_auth); ssl_opts = test_framework_get_ssl_opts (); /* client uses SSL once SSL options are set, regardless of "ssl=true" */ for (add_ssl_to_uri = 0; add_ssl_to_uri < 2; add_ssl_to_uri++) { if (add_ssl_to_uri) { uri = mongoc_uri_new (uri_str_auth_ssl); } else { uri = mongoc_uri_new (uri_str_auth); } if (pooled) { pool = mongoc_client_pool_new (uri); mongoc_client_pool_set_ssl_opts (pool, ssl_opts); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new_from_uri (uri); mongoc_client_set_ssl_opts (client, ssl_opts); } /* any operation */ ret = mongoc_client_command_simple (client, "admin", tmp_bson ("{'ping': 1}"), NULL, NULL, &error); if (test_framework_get_ssl ()) { ASSERT_OR_PRINT (ret, error); } else { /* TODO: CDRIVER-936 check the err msg has "SSL handshake failed" */ ASSERT (!ret); ASSERT_CMPINT (MONGOC_ERROR_SERVER_SELECTION, ==, error.domain); } if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } mongoc_uri_destroy (uri); } bson_free (uri_str_auth_ssl); bson_free (uri_str_auth); bson_free (uri_str); bson_free (host); }; static void test_ssl_single (void) { _test_mongoc_client_ssl_opts (false); } static void test_ssl_pooled (void) { _test_mongoc_client_ssl_opts (true); } #else /* MONGOC_ENABLE_SSL is not defined */ static void test_mongoc_client_ssl_disabled (void) { suppress_one_message (); ASSERT (NULL == mongoc_client_new ("mongodb://host/?ssl=true")); } #endif void test_client_install (TestSuite *suite) { #ifdef TODO_CDRIVER_689 TestSuite_Add (suite, "/Client/wire_version", test_wire_version); #endif if (getenv ("MONGOC_CHECK_IPV6")) { /* try to validate ipv6 too */ TestSuite_Add (suite, "/Client/ipv6", test_mongoc_client_ipv6); } TestSuite_AddFull (suite, "/Client/authenticate", test_mongoc_client_authenticate, NULL, NULL, should_run_auth_tests); TestSuite_AddFull (suite, "/Client/authenticate_failure", test_mongoc_client_authenticate_failure, NULL, NULL, should_run_auth_tests); TestSuite_AddFull (suite, "/Client/authenticate_timeout", test_mongoc_client_authenticate_timeout, NULL, NULL, should_run_auth_tests); TestSuite_Add (suite, "/Client/command", test_mongoc_client_command); TestSuite_Add (suite, "/Client/command_secondary", test_mongoc_client_command_secondary); TestSuite_Add (suite, "/Client/command_not_found/cursor", test_command_not_found); TestSuite_Add (suite, "/Client/command_not_found/simple", test_command_not_found_simple); TestSuite_Add (suite, "/Client/unavailable_seeds", test_unavailable_seeds); TestSuite_Add (suite, "/Client/rs_seeds_no_connect/single", test_rs_seeds_no_connect_single); TestSuite_Add (suite, "/Client/rs_seeds_no_connect/pooled", test_rs_seeds_no_connect_pooled); TestSuite_Add (suite, "/Client/rs_seeds_connect/single", test_rs_seeds_connect_single); TestSuite_Add (suite, "/Client/rs_seeds_connect/pooled", test_rs_seeds_connect_pooled); TestSuite_Add (suite, "/Client/rs_seeds_reconnect/single", test_rs_seeds_reconnect_single); TestSuite_Add (suite, "/Client/rs_seeds_reconnect/pooled", test_rs_seeds_reconnect_pooled); TestSuite_Add (suite, "/Client/mongos_seeds_no_connect/single", test_mongos_seeds_no_connect_single); TestSuite_Add (suite, "/Client/mongos_seeds_no_connect/pooled", test_mongos_seeds_no_connect_pooled); TestSuite_Add (suite, "/Client/mongos_seeds_connect/single", test_mongos_seeds_connect_single); TestSuite_Add (suite, "/Client/mongos_seeds_connect/pooled", test_mongos_seeds_connect_pooled); TestSuite_Add (suite, "/Client/mongos_seeds_reconnect/single", test_mongos_seeds_reconnect_single); TestSuite_Add (suite, "/Client/mongos_seeds_reconnect/pooled", test_mongos_seeds_reconnect_pooled); TestSuite_Add (suite, "/Client/recovering", test_recovering); TestSuite_Add (suite, "/Client/server_status", test_server_status); TestSuite_Add (suite, "/Client/database_names", test_get_database_names); TestSuite_AddFull (suite, "/Client/connect/uds", test_mongoc_client_unix_domain_socket, NULL, NULL, test_framework_skip_if_windows); TestSuite_Add (suite, "/Client/mismatched_me", test_mongoc_client_mismatched_me); #ifdef TODO_CDRIVER_689 TestSuite_Add (suite, "/Client/wire_version", test_wire_version); #endif #ifdef MONGOC_ENABLE_SSL TestSuite_Add (suite, "/Client/ssl_opts/single", test_ssl_single); TestSuite_Add (suite, "/Client/ssl_opts/pooled", test_ssl_pooled); #else TestSuite_Add (suite, "/Client/ssl_disabled", test_mongoc_client_ssl_disabled); #endif } libmongoc-1.3.1/tests/test-mongoc-cluster.c000066400000000000000000000145721264720626300207320ustar00rootroot00000000000000#include #include "mongoc-client-private.h" #include "mongoc-uri-private.h" #include "mock_server/mock-server.h" #include "mock_server/future.h" #include "mock_server/future-functions.h" #include "mongoc-tests.h" #include "TestSuite.h" #include "test-libmongoc.h" #include "test-conveniences.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "cluster-test" static uint32_t server_id_for_reads (mongoc_cluster_t *cluster) { bson_error_t error; mongoc_server_stream_t *server_stream; uint32_t id; server_stream = mongoc_cluster_stream_for_reads (cluster, NULL, &error); ASSERT_OR_PRINT (server_stream, error); id = server_stream->sd->id; mongoc_server_stream_cleanup (server_stream); return id; } static void test_get_max_bson_obj_size (void) { mongoc_server_description_t *sd; mongoc_cluster_node_t *node; mongoc_client_pool_t *pool; mongoc_client_t *client; int32_t max_bson_obj_size = 16; uint32_t id; /* single-threaded */ client = test_framework_client_new (); assert (client); id = server_id_for_reads (&client->cluster); sd = (mongoc_server_description_t *)mongoc_set_get (client->topology->description.servers, id); sd->max_bson_obj_size = max_bson_obj_size; assert (max_bson_obj_size == mongoc_cluster_get_max_bson_obj_size (&client->cluster)); mongoc_client_destroy (client); /* multi-threaded */ pool = test_framework_client_pool_new (); client = mongoc_client_pool_pop (pool); id = server_id_for_reads (&client->cluster); node = (mongoc_cluster_node_t *)mongoc_set_get (client->cluster.nodes, id); node->max_bson_obj_size = max_bson_obj_size; assert (max_bson_obj_size == mongoc_cluster_get_max_bson_obj_size (&client->cluster)); mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } static void test_get_max_msg_size (void) { mongoc_server_description_t *sd; mongoc_cluster_node_t *node; mongoc_client_pool_t *pool; mongoc_client_t *client; int32_t max_msg_size = 32; uint32_t id; /* single-threaded */ client = test_framework_client_new (); id = server_id_for_reads (&client->cluster); sd = (mongoc_server_description_t *)mongoc_set_get (client->topology->description.servers, id); sd->max_msg_size = max_msg_size; assert (max_msg_size == mongoc_cluster_get_max_msg_size (&client->cluster)); mongoc_client_destroy (client); /* multi-threaded */ pool = test_framework_client_pool_new (); client = mongoc_client_pool_pop (pool); id = server_id_for_reads (&client->cluster); node = (mongoc_cluster_node_t *)mongoc_set_get (client->cluster.nodes, id); node->max_msg_size = max_msg_size; assert (max_msg_size == mongoc_cluster_get_max_msg_size (&client->cluster)); mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } #define ASSERT_CURSOR_ERR() do { \ char *error_message = bson_strdup_printf ( \ "Failed to read 4 bytes from socket within %d milliseconds.", \ socket_timeout_ms); \ assert (!future_get_bool (future)); \ assert (mongoc_cursor_error (cursor, &error)); \ ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_STREAM); \ ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_STREAM_SOCKET); \ ASSERT_CMPSTR (error.message, error_message); \ bson_free (error_message); \ } while (0) #define START_QUERY(client_port_variable) do { \ cursor = mongoc_collection_find (collection, \ MONGOC_QUERY_NONE, \ 0, 0, 0, tmp_bson ("{}"), \ NULL, NULL); \ future = future_cursor_next (cursor, &doc); \ request = mock_server_receives_query (server, "test.test", \ MONGOC_QUERY_SLAVE_OK, 0, 0, \ "{}", NULL); \ client_port_variable = request_get_client_port (request); \ } while (0) #define CLEANUP_QUERY() do { \ request_destroy (request); \ future_destroy (future); \ mongoc_cursor_destroy (cursor); \ } while (0) /* test that we reconnect a cluster node after disconnect */ static void _test_cluster_node_disconnect (bool pooled) { mock_server_t *server; const int32_t socket_timeout_ms = 100; mongoc_uri_t *uri; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; mongoc_collection_t *collection; const bson_t *doc; mongoc_cursor_t *cursor; future_t *future; request_t *request; uint16_t client_port_0, client_port_1; bson_error_t error; server = mock_server_with_autoismaster (0); mock_server_run (server); uri = mongoc_uri_copy (mock_server_get_uri (server)); mongoc_uri_set_option_as_int32 (uri, "socketTimeoutMS", socket_timeout_ms); if (pooled) { pool = mongoc_client_pool_new (uri); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new_from_uri (uri); } collection = mongoc_client_get_collection (client, "test", "test"); /* query 0 fails. set client_port_0 to the port used by the query. */ START_QUERY (client_port_0); if (pooled) { suppress_one_message (); } mock_server_resets (request); ASSERT_CURSOR_ERR (); CLEANUP_QUERY (); /* query 1 opens a new socket. set client_port_1 to the new port. */ START_QUERY (client_port_1); ASSERT_CMPINT (client_port_1, !=, client_port_0); mock_server_replies_simple (request, "{'a': 1}"); /* success! */ BSON_ASSERT (future_get_bool (future)); CLEANUP_QUERY (); mongoc_collection_destroy (collection); if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } mongoc_uri_destroy (uri); mock_server_destroy (server); } static void test_cluster_node_disconnect_single (void) { _test_cluster_node_disconnect (false); } static void test_cluster_node_disconnect_pooled (void) { _test_cluster_node_disconnect (true); } void test_cluster_install (TestSuite *suite) { TestSuite_Add (suite, "/Cluster/test_get_max_bson_obj_size", test_get_max_bson_obj_size); TestSuite_Add (suite, "/Cluster/test_get_max_msg_size", test_get_max_msg_size); TestSuite_Add (suite, "/Cluster/disconnect/single", test_cluster_node_disconnect_single); TestSuite_Add (suite, "/Cluster/disconnect/pooled", test_cluster_node_disconnect_pooled); } libmongoc-1.3.1/tests/test-mongoc-collection-find.c000066400000000000000000001022611264720626300223130ustar00rootroot00000000000000#include #include #include #include "TestSuite.h" #include "test-libmongoc.h" #include "test-conveniences.h" #include "mock_server/mock-server.h" #include "mock_server/future.h" #include "mock_server/future-functions.h" typedef struct { /* if do_live is true (the default), actually query the server using the * appropriate wire protocol: either OP_QUERY or a "find" command */ bool do_live; bool requires_wire_version_4; const char *docs; bson_t *docs_bson; const char *query_input; bson_t *query_bson; const char *fields; bson_t *fields_bson; const char *expected_find_command; const char *expected_op_query; uint32_t n_return; const char *expected_result; bson_t *expected_result_bson; uint32_t skip; uint32_t limit; uint32_t batch_size; mongoc_query_flags_t flags; mongoc_read_prefs_t *read_prefs; const char *filename; int lineno; const char *funcname; uint32_t n_results; } test_collection_find_t; #define TEST_COLLECTION_FIND_INIT { true, false } static void _insert_test_docs (mongoc_collection_t *collection, const bson_t *docs) { bson_iter_t iter; uint32_t len; const uint8_t *data; bson_t doc; bool r; bson_error_t error; bson_iter_init (&iter, docs); while (bson_iter_next (&iter)) { bson_iter_document (&iter, &len, &data); bson_init_static (&doc, data, len); r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, &doc, NULL, &error); ASSERT_OR_PRINT (r, error); } } static void _check_cursor (mongoc_cursor_t *cursor, test_collection_find_t *test_data) { const bson_t *doc; bson_t actual_result = BSON_INITIALIZER; char str[16]; const char *key; uint32_t i = 0; bson_error_t error; while (mongoc_cursor_next (cursor, &doc)) { bson_uint32_to_string (i, &key, str, sizeof str); bson_append_document (&actual_result, key, -1, doc); i++; } ASSERT_OR_PRINT (!mongoc_cursor_error (cursor, &error), error); if (i != test_data->n_results) { fprintf (stderr, "expect %d results, got %d\n", test_data->n_results, i); abort (); } ASSERT (match_json (&actual_result, false /* is_command */, test_data->filename, test_data->lineno, test_data->funcname, test_data->expected_result)); bson_destroy (&actual_result); } static void _test_collection_find_live (test_collection_find_t *test_data) { mongoc_client_t *client; mongoc_database_t *database; char *collection_name; mongoc_collection_t *collection; char *drop_cmd; bool r; bson_error_t error; mongoc_cursor_t *cursor; client = test_framework_client_new (); database = mongoc_client_get_database (client, "test"); collection_name = gen_collection_name ("test"); collection = mongoc_database_create_collection ( database, collection_name, tmp_bson ("{'capped': true, 'size': 10000}"), &error); ASSERT_OR_PRINT (collection, error); _insert_test_docs (collection, test_data->docs_bson); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, test_data->skip, test_data->limit, test_data->batch_size, test_data->query_bson, test_data->fields_bson, test_data->read_prefs); _check_cursor (cursor, test_data); drop_cmd = bson_strdup_printf ("{'drop': '%s'}", collection_name); r = mongoc_client_command_simple (client, "test", tmp_bson (drop_cmd), NULL, NULL, &error); ASSERT_OR_PRINT (r, error); bson_free (drop_cmd); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); bson_free (collection_name); mongoc_client_destroy (client); } typedef request_t *(*check_request_fn_t) (mock_server_t *server, test_collection_find_t *test_data); typedef void (*reply_fn_t) (request_t *request, test_collection_find_t *test_data); /*-------------------------------------------------------------------------- * * _test_collection_op_query_or_find_command -- * * Start a mock server with @max_wire_version, connect a client, and * execute @test_data->query. Use the @check_request_fn callback to * verify the client formatted the query correctly, and @reply_fn to * response to the client. Check that the client cursor's results * match @test_data->expected_result. * *-------------------------------------------------------------------------- */ static void _test_collection_op_query_or_find_command ( test_collection_find_t *test_data, check_request_fn_t check_request_fn, reply_fn_t reply_fn, int32_t max_wire_version) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; future_t *future; request_t *request; const bson_t *doc; bool cursor_next_result; bson_t actual_result = BSON_INITIALIZER; char str[16]; const char *key; uint32_t i = 0; server = mock_server_with_autoismaster (max_wire_version); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); cursor = mongoc_collection_find (collection, test_data->flags, test_data->skip, test_data->limit, test_data->batch_size, test_data->query_bson, test_data->fields_bson, test_data->read_prefs); ASSERT_OR_PRINT (!mongoc_cursor_error (cursor, &error), error); future = future_cursor_next (cursor, &doc); request = check_request_fn (server, test_data); ASSERT (request); reply_fn (request, test_data); cursor_next_result = future_get_bool (future); /* did we expect at least one result? */ ASSERT (cursor_next_result == (test_data->n_results > 0)); assert (!mongoc_cursor_error (cursor, NULL)); if (cursor_next_result) { bson_append_document (&actual_result, "0", -1, doc); i++; /* check remaining results */ while (mongoc_cursor_next (cursor, &doc)) { bson_uint32_to_string (i, &key, str, sizeof str); bson_append_document (&actual_result, key, -1, doc); i++; } assert (!mongoc_cursor_error (cursor, NULL)); } if (i != test_data->n_results) { fprintf (stderr, "Expected %d results, got %d\n", test_data->n_results, i); abort (); } ASSERT (match_json (&actual_result, false /* is_command */, test_data->filename, test_data->lineno, test_data->funcname, test_data->expected_result)); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } static request_t * _check_op_query (mock_server_t *server, test_collection_find_t *test_data) { mongoc_query_flags_t flags; flags = test_data->flags | MONGOC_QUERY_SLAVE_OK; return mock_server_receives_query (server, "db.collection", flags, test_data->skip, test_data->n_return, test_data->expected_op_query, test_data->fields); } static void _reply_to_op_query (request_t *request, test_collection_find_t *test_data) { bson_t *docs; int i; bson_iter_t iter; uint32_t len; const uint8_t *data; docs = bson_malloc (test_data->n_results * sizeof (bson_t)); bson_iter_init (&iter, test_data->expected_result_bson); for (i = 0; i < test_data->n_results; i++) { bson_iter_next (&iter); bson_iter_document (&iter, &len, &data); bson_init_static (&docs[i], data, len); } mock_server_reply_multi (request, MONGOC_REPLY_NONE, docs, test_data->n_results, 0 /* cursor_id */); } static void _test_collection_op_query (test_collection_find_t *test_data) { _test_collection_op_query_or_find_command (test_data, _check_op_query, _reply_to_op_query, 3 /* wire version */); } static request_t * _check_find_command (mock_server_t *server, test_collection_find_t *test_data) { /* Server Selection Spec: all queries to standalone set slaveOk. * * Find, getMore And killCursors Commands Spec: "When sending a find command * rather than a legacy OP_QUERY find only the slaveOk flag is honored". */ return mock_server_receives_command (server, "db", MONGOC_QUERY_SLAVE_OK, test_data->expected_find_command); } static void _reply_to_find_command (request_t *request, test_collection_find_t *test_data) { const char *result_json; char *reply_json; result_json = test_data->expected_result ? test_data->expected_result : "[]"; reply_json = bson_strdup_printf ("{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'db.collection'," " 'firstBatch': %s}}", result_json); mock_server_replies_simple (request, reply_json); bson_free (reply_json); } static void _test_collection_find_command (test_collection_find_t *test_data) { _test_collection_op_query_or_find_command (test_data, _check_find_command, _reply_to_find_command, 4 /* max wire version */); } static void _test_collection_find (test_collection_find_t *test_data) { /* catch typos in tests' setup */ if (test_data->query_input) { BSON_ASSERT (test_data->requires_wire_version_4 || test_data->expected_op_query); } BSON_ASSERT (test_data->expected_find_command); test_data->docs_bson = tmp_bson (test_data->docs); test_data->query_bson = tmp_bson (test_data->query_input); test_data->fields_bson = test_data->fields ? tmp_bson (test_data->fields) : NULL; test_data->expected_result_bson = tmp_bson (test_data->expected_result); test_data->n_results = bson_count_keys (test_data->expected_result_bson); if (test_data->do_live && (!test_data->requires_wire_version_4 || test_framework_max_wire_version_at_least (4))) { _test_collection_find_live (test_data); } if (!test_data->requires_wire_version_4) { _test_collection_op_query (test_data); } _test_collection_find_command (test_data); } static void test_dollar_query (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}, {'_id': 2}]"; test_data.query_input = "{'$query': {'_id': 1}}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {'_id': 1}}"; test_data.expected_result = "[{'_id': 1}]"; _test_collection_find (&test_data); } static void test_dollar_or (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}, {'_id': 2}, {'_id': 3}]"; test_data.query_input = "{'$or': [{'_id': 1}, {'_id': 3}]}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {'$or': [{'_id': 1}, {'_id': 3}]}}"; test_data.expected_result = "[{'_id': 1}, {'_id': 3}]"; _test_collection_find (&test_data); } /* test that we can query for a document by a key named "filter" */ static void test_key_named_filter (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1, 'filter': 1}, {'_id': 2, 'filter': 2}]"; test_data.query_input = "{'$query': {'filter': 2}}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {'filter': 2}}"; test_data.expected_result = "[{'_id': 2, 'filter': 2}]"; _test_collection_find (&test_data); } /* test '$query': {'filter': {'i': 2}} */ static void test_op_query_subdoc_named_filter (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1, 'filter': {'i': 1}}, {'_id': 2, 'filter': {'i': 2}}]"; test_data.query_input = "{'$query': {'filter': {'i': 2}}}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {'filter': {'i': 2}}}"; test_data.expected_result = "[{'_id': 2, 'filter': {'i': 2}}]"; _test_collection_find (&test_data); } /* test new-style 'filter': {'filter': {'i': 2}} */ static void test_find_cmd_subdoc_named_filter (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1, 'filter': {'i': 1}}, {'_id': 2, 'filter': {'i': 2}}]"; test_data.query_input = "{'filter': {'filter': {'i': 2}}}"; test_data.expected_find_command = "{'find': 'collection', 'filter': {'filter': {'i': 2}}}"; test_data.expected_result = "[{'_id': 2, 'filter': {'i': 2}}]"; /* this only works if you know you're talking wire version 4 */ test_data.requires_wire_version_4 = true; _test_collection_find (&test_data); } /* test new-style 'filter': {'filter': {'i': 2}}, 'singleBatch': true * we just use singleBatch to prove that a new-style option can be passed * alongside 'filter' */ static void test_find_cmd_subdoc_named_filter_with_option (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1, 'filter': {'i': 1}}, {'_id': 2, 'filter': {'i': 2}}]"; test_data.query_input = "{'filter': {'filter': {'i': 2}}, 'singleBatch': true}"; test_data.expected_find_command = "{'find': 'collection', 'filter': {'filter': {'i': 2}}, 'singleBatch': true}"; test_data.expected_result = "[{'_id': 2, 'filter': {'i': 2}}]"; /* this only works if you know you're talking wire version 4 */ test_data.requires_wire_version_4 = true; _test_collection_find (&test_data); } /* test future-compatibility with a new server's find command options */ static void test_newoption (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.query_input = "{'filter': {'_id': 1}, 'newOption': true}"; test_data.expected_find_command = "{'find': 'collection', 'filter': {'_id': 1}, 'newOption': true}"; /* won't work today */ test_data.do_live = false; test_data.requires_wire_version_4 = true; _test_collection_find (&test_data); } static void test_orderby (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}, {'_id': 2}]"; test_data.query_input = "{'$query': {}, '$orderby': {'_id': -1}}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'sort': {'_id': -1}}"; test_data.expected_result = "[{'_id': 2}, {'_id': 1}]"; _test_collection_find (&test_data); } static void test_fields (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1, 'a': 1, 'b': 2}]"; test_data.fields = "{'_id': 0, 'b': 1}"; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'projection': {'_id': 0, 'b': 1}}"; test_data.expected_result = "[{'b': 2}]"; _test_collection_find (&test_data); } static void test_int_modifiers (void) { const char *modifiers[] = { "maxScan", "maxTimeMS", }; const char *mod; size_t i; char *query; char *find_command; test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.expected_result = test_data.docs = "[{'_id': 1}]"; for (i = 0; i < sizeof (modifiers) / sizeof (const char *); i++) { mod = modifiers[i]; query = bson_strdup_printf ("{'$query': {}, '$%s': 9999}", mod); /* find command has same modifier, without the $-prefix */ find_command = bson_strdup_printf ( "{'find': 'collection', 'filter': {}, '%s': 9999}", mod); test_data.expected_op_query = test_data.query_input = query; test_data.expected_find_command = find_command; _test_collection_find (&test_data); bson_free (query); bson_free (find_command); } } static void test_index_spec_modifiers (void) { /* don't include $max, it needs a slightly different argument to succeed */ const char *modifiers[] = { "hint", "min", }; const char *mod; size_t i; char *query; char *find_command; test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.expected_result = test_data.docs = "[{'_id': 1}]"; for (i = 0; i < sizeof (modifiers) / sizeof (const char *); i++) { mod = modifiers[i]; query = bson_strdup_printf ("{'$query': {}, '$%s': {'_id': 1}}", mod); /* find command has same modifier, without the $-prefix */ find_command = bson_strdup_printf ( "{'find': 'collection', 'filter': {}, '%s': {'_id': 1}}", mod); test_data.expected_op_query = test_data.query_input = query; test_data.expected_find_command = find_command; _test_collection_find (&test_data); bson_free (query); bson_free (find_command); } } static void test_comment (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}]"; test_data.query_input = "{'$query': {}, '$comment': 'hi'}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'comment': 'hi'}"; test_data.expected_result = "[{'_id': 1}]"; _test_collection_find (&test_data); } static void test_max (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}]"; test_data.query_input = "{'$query': {}, '$max': {'_id': 100}}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'max': {'_id': 100}}"; test_data.expected_result = "[{'_id': 1}]"; _test_collection_find (&test_data); } static void test_snapshot (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}]"; test_data.query_input = "{'$query': {}, '$snapshot': true}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'snapshot': true}"; test_data.expected_result = "[{'_id': 1}]"; _test_collection_find (&test_data); } /* $showDiskLoc becomes showRecordId */ static void test_diskloc (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}]"; test_data.query_input = "{'$query': {}, '$showDiskLoc': true}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'showRecordId': true}"; test_data.expected_result = "[{'_id': 1}]"; _test_collection_find (&test_data); } static void test_returnkey (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}]"; test_data.query_input = "{'$query': {}, '$returnKey': true}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'returnKey': true}"; test_data.expected_result = "[{}]"; _test_collection_find (&test_data); } static void test_skip (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}, {'_id': 2}]"; test_data.skip = 1; test_data.query_input = "{'$query': {}, '$orderby': {'_id': 1}}"; test_data.expected_op_query = test_data.query_input; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'sort': {'_id': 1}, 'skip': {'$numberLong': '1'}}"; test_data.expected_result = "[{'_id': 2}]"; _test_collection_find (&test_data); } static void test_batch_size (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}]"; test_data.batch_size = 2; test_data.n_return = 2; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'batchSize': 2}"; test_data.expected_result = "[{'_id': 1}]"; _test_collection_find (&test_data); } static void test_limit (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.docs = "[{'_id': 1}, {'_id': 2}, {'_id': 3}]"; test_data.limit = 2; test_data.query_input = "{'$query': {}, '$orderby': {'_id': 1}}"; test_data.expected_op_query = test_data.query_input; test_data.n_return = 2; test_data.expected_find_command = "{'find': 'collection', 'filter': {}, 'sort': {'_id': 1}, 'limit': {'$numberLong': '2'}}"; test_data.expected_result = "[{'_id': 1}, {'_id': 2}]"; _test_collection_find (&test_data); } static void test_unrecognized_dollar_option (void) { test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; test_data.query_input = "{'$query': {'a': 1}, '$dumb': 1}"; test_data.expected_find_command = "{'find': 'collection', 'filter': {'a': 1}, '$dumb': 1}"; test_data.requires_wire_version_4 = true; test_data.do_live = false; _test_collection_find (&test_data); } static void test_query_flags (void) { int i; char *find_cmd; test_collection_find_t test_data = TEST_COLLECTION_FIND_INIT; typedef struct { mongoc_query_flags_t flag; const char *name; } flag_and_name_t; /* slaveok is still in the wire protocol header, exhaust is not supported */ flag_and_name_t flags_and_names[] = { { MONGOC_QUERY_TAILABLE_CURSOR, "tailable" }, { MONGOC_QUERY_OPLOG_REPLAY, "oplogReplay" }, { MONGOC_QUERY_NO_CURSOR_TIMEOUT, "noCursorTimeout" }, { MONGOC_QUERY_AWAIT_DATA, "awaitData" }, { MONGOC_QUERY_PARTIAL, "allowPartialResults" }, }; test_data.expected_result = test_data.docs = "[{'_id': 1}]"; for (i = 0; i < (sizeof flags_and_names) / (sizeof (flag_and_name_t)); i++) { find_cmd = bson_strdup_printf ( "{'find': 'collection', 'filter': {}, '%s': true}", flags_and_names[i].name); test_data.flags = flags_and_names[i].flag; test_data.expected_find_command = find_cmd; _test_collection_find (&test_data); bson_free (find_cmd); } } static void test_getmore_batch_size (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; future_t *future; request_t *request; const bson_t *doc; uint32_t batch_sizes[] = { 0, 1, 2 }; size_t i; char *batch_size_json; bson_error_t error; server = mock_server_with_autoismaster (4); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); for (i = 0; i < sizeof (batch_sizes) / sizeof (uint32_t); i++) { cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, batch_sizes[i], tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); if (batch_sizes[i]) { batch_size_json = bson_strdup_printf ("%u", batch_sizes[i]); } else { batch_size_json = bson_strdup ("{'$exists': false}"); } request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{'find': 'collection', 'filter': {}, 'batchSize': %s}", batch_size_json); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'db.collection'," " 'firstBatch': []}}"); /* no result */ ASSERT (!future_get_bool (future)); ASSERT_OR_PRINT (!mongoc_cursor_error (cursor, &error), error); future_destroy (future); request_destroy (request); bson_free (batch_size_json); mongoc_cursor_destroy (cursor); } mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } static void test_getmore_invalid_reply (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; future_t *future; request_t *request; const bson_t *doc; bson_error_t error; server = mock_server_with_autoismaster (4); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{'find': 'collection', 'filter': {}}"); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': {'$numberLong': '123'}," " 'ns': 'db.collection'," " 'firstBatch': [{}]}}"); ASSERT (future_get_bool (future)); future_destroy (future); request_destroy (request); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{'getMore': {'$numberLong': '123'}, 'collection': 'collection'}"); /* missing "cursor" */ mock_server_replies_simple (request, "{'ok': 1}"); ASSERT (!future_get_bool (future)); ASSERT (mongoc_cursor_error (cursor, &error)); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_PROTOCOL); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_PROTOCOL_INVALID_REPLY); ASSERT_CONTAINS (error.message, "getMore"); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } static void test_getmore_await (void) { typedef struct { mongoc_query_flags_t flags; bool expect_await; } await_test_t; await_test_t await_tests[] = { { MONGOC_QUERY_NONE, false }, { MONGOC_QUERY_TAILABLE_CURSOR, false }, { MONGOC_QUERY_AWAIT_DATA, false }, { MONGOC_QUERY_TAILABLE_CURSOR | MONGOC_QUERY_AWAIT_DATA, true }, }; mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; future_t *future; request_t *request; const bson_t *doc; size_t i; char *max_time_json; server = mock_server_with_autoismaster (4); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); for (i = 3; i < sizeof (await_tests) / sizeof (await_test_t); i++) { cursor = mongoc_collection_find ( collection, await_tests[i].flags, 0, 0, 0, tmp_bson ("{}"), NULL, NULL); ASSERT_CMPINT (0, ==, mongoc_cursor_get_max_await_time_ms (cursor)); mongoc_cursor_set_max_await_time_ms (cursor, 123); future = future_cursor_next (cursor, &doc); /* only the slave ok bit is still in the query header */ request = mock_server_receives_command (server, "db", MONGOC_QUERY_SLAVE_OK, "{'find': 'collection'}"); /* reply with cursor id 1 */ mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 1," " 'ns': 'db.collection'," " 'firstBatch': [{}]}}"); /* no result or error */ ASSERT (future_get_bool (future)); future_destroy (future); request_destroy (request); future = future_cursor_next (cursor, &doc); if (await_tests[i].expect_await) { max_time_json = "123"; } else { max_time_json = "{'$exists': false}"; } /* only the slave ok bit is still in the query header */ request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{'getMore': {'$numberLong': '1'}," " 'collection': 'collection'," " 'maxTimeMS': %s}", max_time_json); assert (request); /* reply with cursor id 0 */ mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'db.collection'," " 'nextBatch': []}}"); /* no result or error */ ASSERT (!future_get_bool (future)); ASSERT (!mongoc_cursor_error (cursor, NULL)); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); } mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } void test_collection_find_install (TestSuite *suite) { TestSuite_Add (suite, "/Collection/find/dollar_query", test_dollar_query); TestSuite_Add (suite, "/Collection/find/dollar_or", test_dollar_or); TestSuite_Add (suite, "/Collection/find/key_named_filter", test_key_named_filter); TestSuite_Add (suite, "/Collection/find/cmd/subdoc_named_filter", test_find_cmd_subdoc_named_filter); TestSuite_Add (suite, "/Collection/find/query/subdoc_named_filter", test_op_query_subdoc_named_filter); TestSuite_Add (suite, "/Collection/find/newoption", test_newoption); TestSuite_Add (suite, "/Collection/find/cmd/subdoc_named_filter_with_option", test_find_cmd_subdoc_named_filter_with_option); TestSuite_Add (suite, "/Collection/find/orderby", test_orderby); TestSuite_Add (suite, "/Collection/find/fields", test_fields); TestSuite_Add (suite, "/Collection/find/modifiers/integer", test_int_modifiers); TestSuite_Add (suite, "/Collection/find/modifiers/index_spec", test_index_spec_modifiers); TestSuite_Add (suite, "/Collection/find/comment", test_comment); TestSuite_Add (suite, "/Collection/find/max", test_max); TestSuite_Add (suite, "/Collection/find/modifiers/bool", test_snapshot); TestSuite_Add (suite, "/Collection/find/showdiskloc", test_diskloc); TestSuite_Add (suite, "/Collection/find/returnkey", test_returnkey); TestSuite_Add (suite, "/Collection/find/skip", test_skip); TestSuite_Add (suite, "/Collection/find/batch_size", test_batch_size); TestSuite_Add (suite, "/Collection/find/limit", test_limit); TestSuite_Add (suite, "/Collection/find/unrecognized", test_unrecognized_dollar_option); TestSuite_Add (suite, "/Collection/find/flags", test_query_flags); TestSuite_Add (suite, "/Collection/getmore/batch_size", test_getmore_batch_size); TestSuite_Add (suite, "/Collection/getmore/invalid_reply", test_getmore_invalid_reply); TestSuite_Add (suite, "/Collection/getmore/await", test_getmore_await); } libmongoc-1.3.1/tests/test-mongoc-collection.c000066400000000000000000002556651264720626300214160ustar00rootroot00000000000000#include #include #include #include #include #include "TestSuite.h" #include "test-libmongoc.h" #include "test-conveniences.h" #include "mongoc-tests.h" #include "mock_server/future-functions.h" #include "mock_server/mock-server.h" static mongoc_database_t * get_test_database (mongoc_client_t *client) { return mongoc_client_get_database (client, "test"); } static mongoc_collection_t * get_test_collection (mongoc_client_t *client, const char *prefix) { mongoc_collection_t *ret; char *str; str = gen_collection_name (prefix); ret = mongoc_client_get_collection (client, "test", str); bson_free (str); return ret; } static void test_copy (void) { mongoc_database_t *database; mongoc_collection_t *collection; mongoc_collection_t *copy; mongoc_client_t *client; client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_insert"); ASSERT (collection); copy = mongoc_collection_copy(collection); ASSERT (copy); ASSERT (copy->client == collection->client); ASSERT (strcmp(copy->ns, collection->ns) == 0); mongoc_collection_destroy(copy); mongoc_collection_destroy(collection); mongoc_database_destroy(database); mongoc_client_destroy(client); } static void test_insert (void) { mongoc_database_t *database; mongoc_collection_t *collection; mongoc_client_t *client; bson_context_t *context; bson_error_t error; bool r; bson_oid_t oid; unsigned i; bson_t b; client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_insert"); ASSERT (collection); mongoc_collection_drop(collection, &error); context = bson_context_new(BSON_CONTEXT_NONE); ASSERT (context); for (i = 0; i < 10; i++) { bson_init(&b); bson_oid_init(&oid, context); bson_append_oid(&b, "_id", 3, &oid); bson_append_utf8(&b, "hello", 5, "/world", 5); ASSERT_OR_PRINT (mongoc_collection_insert( collection, MONGOC_INSERT_NONE, &b, NULL, &error), error); bson_destroy(&b); } bson_init (&b); BSON_APPEND_INT32 (&b, "$hello", 1); r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, &b, NULL, &error); ASSERT (!r); ASSERT (error.domain == MONGOC_ERROR_BSON); ASSERT (error.code == MONGOC_ERROR_BSON_INVALID); bson_destroy (&b); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy(collection); mongoc_database_destroy(database); bson_context_destroy(context); mongoc_client_destroy(client); } /* CDRIVER-759, a 2.4 mongos responds to getLastError after an oversized insert: * * { err: "assertion src/mongo/s/strategy_shard.cpp:461", n: 0, ok: 1.0 } * * There's an "err" but no "code". */ static void test_legacy_insert_oversize_mongos (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; bson_t b = BSON_INITIALIZER; bson_error_t error; future_t *future; request_t *request; server = mock_server_with_autoismaster (0); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test"); future = future_collection_insert (collection, MONGOC_INSERT_NONE, &b, NULL, &error); request = mock_server_receives_insert (server, "test.test", MONGOC_INSERT_NONE, "{}"); request_destroy (request); request = mock_server_receives_gle (server, "test"); mock_server_replies_simple (request, "{'err': 'oh no!', 'n': 0, 'ok': 1}"); ASSERT (!future_get_bool (future)); ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COLLECTION_INSERT_FAILED, "oh no!"); request_destroy (request); future_destroy (future); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mock_server_destroy (server); } static void test_insert_bulk (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; bson_context_t *context; bson_error_t error; bool r; bson_oid_t oid; unsigned i; bson_t q; bson_t b[10]; bson_t *bptr[10]; int64_t count; client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_insert_bulk"); ASSERT (collection); mongoc_collection_drop(collection, &error); context = bson_context_new(BSON_CONTEXT_NONE); ASSERT (context); bson_init(&q); bson_append_int32(&q, "n", -1, 0); for (i = 0; i < 10; i++) { bson_init(&b[i]); bson_oid_init(&oid, context); bson_append_oid(&b[i], "_id", -1, &oid); bson_append_int32(&b[i], "n", -1, i % 2); bptr[i] = &b[i]; } BEGIN_IGNORE_DEPRECATIONS; ASSERT_OR_PRINT (mongoc_collection_insert_bulk (collection, MONGOC_INSERT_NONE, (const bson_t **)bptr, 10, NULL, &error), error); END_IGNORE_DEPRECATIONS; count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &q, 0, 0, NULL, &error); ASSERT (count == 5); for (i = 8; i < 10; i++) { bson_destroy(&b[i]); bson_init(&b[i]); bson_oid_init(&oid, context); bson_append_oid(&b[i], "_id", -1, &oid); bson_append_int32(&b[i], "n", -1, i % 2); bptr[i] = &b[i]; } BEGIN_IGNORE_DEPRECATIONS; r = mongoc_collection_insert_bulk (collection, MONGOC_INSERT_NONE, (const bson_t **)bptr, 10, NULL, &error); END_IGNORE_DEPRECATIONS; ASSERT (!r); ASSERT (error.code == 11000); count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &q, 0, 0, NULL, &error); ASSERT (count == 5); BEGIN_IGNORE_DEPRECATIONS; r = mongoc_collection_insert_bulk (collection, MONGOC_INSERT_CONTINUE_ON_ERROR, (const bson_t **)bptr, 10, NULL, &error); END_IGNORE_DEPRECATIONS; ASSERT (!r); ASSERT (error.code == 11000); count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &q, 0, 0, NULL, &error); ASSERT (count == 6); /* test validate */ for (i = 0; i < 10; i++) { bson_destroy (&b[i]); bson_init (&b[i]); BSON_APPEND_INT32 (&b[i], "$invalid_dollar_prefixed_name", i); bptr[i] = &b[i]; } BEGIN_IGNORE_DEPRECATIONS; r = mongoc_collection_insert_bulk (collection, MONGOC_INSERT_NONE, (const bson_t **)bptr, 10, NULL, &error); END_IGNORE_DEPRECATIONS; ASSERT (!r); ASSERT (error.domain == MONGOC_ERROR_BSON); ASSERT (error.code == MONGOC_ERROR_BSON_INVALID); bson_destroy(&q); for (i = 0; i < 10; i++) { bson_destroy(&b[i]); } ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy(collection); mongoc_database_destroy(database); bson_context_destroy(context); mongoc_client_destroy(client); } static void test_insert_bulk_empty (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; bson_error_t error; bson_t *bptr = NULL; client = test_framework_client_new (); database = get_test_database (client); collection = get_test_collection (client, "test_insert_bulk_empty"); BEGIN_IGNORE_DEPRECATIONS; ASSERT (!mongoc_collection_insert_bulk (collection, MONGOC_INSERT_NONE, (const bson_t **)&bptr, 0, NULL, &error)); END_IGNORE_DEPRECATIONS; ASSERT_CMPINT (MONGOC_ERROR_COLLECTION, ==, error.domain); ASSERT_CMPINT (MONGOC_ERROR_COLLECTION_INSERT_FAILED, ==, error.code); ASSERT_CONTAINS (error.message, "empty insert"); mongoc_collection_destroy(collection); mongoc_database_destroy(database); mongoc_client_destroy(client); } static void auto_ismaster (mock_server_t *server, int32_t max_wire_version, int32_t max_message_size, int32_t max_bson_size, int32_t max_batch_size) { char *response = bson_strdup_printf ( "{'ismaster': true, " " 'maxWireVersion': %d," " 'maxBsonObjectSize': %d," " 'maxMessageSizeBytes': %d," " 'maxWriteBatchSize': %d }", max_wire_version, max_bson_size, max_message_size, max_batch_size); mock_server_auto_ismaster (server, response); bson_free (response); } char * make_string (size_t len) { char *s = (char *)bson_malloc (len); memset (s, 'a', len - 1); s[len - 1] = '\0'; return s; } bson_t * make_document (size_t bytes) { bson_t *bson; bson_oid_t oid; char *s; size_t string_len; bson_oid_init (&oid, NULL); bson = bson_new (); BSON_APPEND_OID (bson, "_id", &oid); /* make the document exactly n bytes by appending a string. a string has * 7 bytes overhead (1 for type code, 2 for key, 4 for length prefix), so * make the string (n_bytes - current_length - 7) bytes long. */ ASSERT_CMPUINT((unsigned int)bytes, >=, bson->len + 7); string_len = bytes - bson->len - 7; s = make_string (string_len); BSON_APPEND_UTF8 (bson, "s", s); bson_free (s); ASSERT_CMPUINT ((unsigned int) bytes, ==, bson->len); return bson; } void make_bulk_insert (bson_t **bsons, int n, size_t bytes) { int i; for (i = 0; i < n; i++) { bsons[i] = make_document (bytes); } } static void destroy_all (bson_t **ptr, int n) { int i; for (i = 0; i < n; i++) { bson_destroy (ptr[i]); } } static void receive_bulk (mock_server_t *server, int n, mongoc_insert_flags_t flags) { request_t *request; request = mock_server_receives_bulk_insert (server, "test.test", flags, n); assert (request); request_destroy (request); request = mock_server_receives_gle (server, "test"); mock_server_replies_simple (request, "{'ok': 1.0, 'n': 0, 'err': null}"); request_destroy (request); } static void test_legacy_bulk_insert_large (void) { enum { N_BSONS = 10 }; mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; bson_t *bsons[N_BSONS]; bson_error_t error; future_t *future; server = mock_server_new (); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test"); /* docs size 50 bytes each */ make_bulk_insert (bsons, N_BSONS, 50); /* max message of 240 bytes, so 4 docs per batch, 3 batches. */ auto_ismaster (server, 0, /* max_wire_version */ 240, /* max_message_size */ 1000, /* max_bson_size */ 1000); /* max_write_batch_size */ future = future_collection_insert_bulk (collection, MONGOC_INSERT_NONE, (const bson_t **) bsons, 10, NULL, &error); receive_bulk (server, 4, MONGOC_INSERT_NONE); receive_bulk (server, 4, MONGOC_INSERT_NONE); receive_bulk (server, 2, MONGOC_INSERT_NONE); ASSERT_OR_PRINT (future_get_bool (future), error); future_destroy (future); destroy_all (bsons, N_BSONS); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mock_server_destroy (server); } /* verify an insert command's "documents" array has keys "0", "1", "2", ... */ static void verify_keys (uint32_t n_documents, const bson_t *insert_command) { bson_iter_t iter; uint32_t len; const uint8_t *data; bson_t document; char str[16]; const char *key; uint32_t i; ASSERT (bson_iter_init_find (&iter, insert_command, "documents")); bson_iter_array (&iter, &len, &data); ASSERT (bson_init_static (&document, data, len)); for (i = 0; i < n_documents; i++) { bson_uint32_to_string (i, &key, str, sizeof str); ASSERT (bson_has_field (&document, key)); } } /* CDRIVER-845: "insert" command must have array keys "0", "1", "2", ... */ static void test_insert_command_keys (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; uint32_t i; bson_t *doc; bson_t reply; bson_error_t error; future_t *future; request_t *request; /* maxWireVersion 3 allows write commands */ server = mock_server_with_autoismaster (3); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "test", "test"); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); for (i = 0; i < 3; i++) { doc = BCON_NEW ("_id", BCON_INT32 (i)); mongoc_bulk_operation_insert (bulk, doc); bson_destroy (doc); } future = future_bulk_operation_execute (bulk, &reply, &error); request = mock_server_receives_command (server, "test", MONGOC_QUERY_NONE, "{'insert': 'test'}"); verify_keys (3, request_get_doc (request, 0)); mock_server_replies_simple (request, "{'ok': 1}"); ASSERT_OR_PRINT (future_get_uint32_t (future), error); bson_destroy (&reply); future_destroy (future); request_destroy (request); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mock_server_destroy (server); } /* number of docs that should go in a batch that starts at "offset" */ int expected_batch_size (const bson_t **bsons, int n_bsons, int max_message_size, int max_bson_size, bool continue_on_err, int *offset, /* IN / OUT */ bool *has_oversized) /* OUT */ { int batch_sz = 0; int msg_sz = 0; bool oversized; int n_oversized = 0; for (; *offset < n_bsons; (*offset)++) { oversized = (bsons[*offset]->len > max_bson_size); if (oversized) { n_oversized++; if (!continue_on_err) { /* stop here */ return batch_sz; } } else { /* not oversized, regular document */ msg_sz += bsons[*offset]->len; if (msg_sz >= max_message_size) { /* batch is full of regular documents */ break; } batch_sz++; } } *has_oversized = (bool) n_oversized; return batch_sz; } static void _test_legacy_bulk_insert (const bson_t **bsons, int n_bsons, bool continue_on_err, const char *err_msg, const char *gle_json, ...) { const int MAX_MESSAGE_SIZE = 300; const int MAX_BSON_SIZE = 200; va_list args; char *gle_json_formatted; mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; bson_error_t error; future_t *future; mongoc_insert_flags_t flags; int offset; bool has_oversized = false; int batch_sz; const bson_t *gle; va_start (args, gle_json); gle_json_formatted = bson_strdupv_printf (gle_json, args); va_end (args); server = mock_server_new (); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test"); auto_ismaster (server, 0, MAX_MESSAGE_SIZE, MAX_BSON_SIZE, 1 /* max_write_batch_size, irrelevant */ ); flags = continue_on_err ? MONGOC_INSERT_CONTINUE_ON_ERROR : MONGOC_INSERT_NONE; future = future_collection_insert_bulk ( collection, flags, bsons, (uint32_t) n_bsons, NULL, &error); offset = 0; /* mock server receives each batch. check each is the right size. */ while ((batch_sz = expected_batch_size (bsons, n_bsons, MAX_MESSAGE_SIZE, MAX_BSON_SIZE, continue_on_err, &offset, &has_oversized))) { receive_bulk (server, batch_sz, flags); if (has_oversized && !continue_on_err) { break; } } /* mongoc_collection_insert_bulk returns false, there was an error */ assert (!future_get_bool (future)); /* TODO: CDRIVER-662, should always be MONGOC_ERROR_BSON */ assert ( (error.domain == MONGOC_ERROR_COMMAND) || (error.domain == MONGOC_ERROR_BSON && error.code == MONGOC_ERROR_BSON_INVALID)); ASSERT_STARTSWITH (error.message, err_msg); gle = mongoc_collection_get_last_error (collection); assert (gle); /* TODO: should contain inserted ids, CDRIVER-703 */ ASSERT_MATCH (gle, gle_json_formatted); future_destroy (future); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mock_server_destroy (server); bson_free (gle_json_formatted); } static void _test_legacy_bulk_insert_oversized_middle (bool continue_on_err) { enum { N_BSONS = 5 }; bson_t *bsons[N_BSONS]; /* first batch */ bsons[0] = make_document (100); bsons[1] = make_document (100); /* second batch */ bsons[2] = make_document (100); bsons[3] = make_document (300); /* too big */ /* final batch, only sent if continue_on_err */ bsons[4] = make_document (100); _test_legacy_bulk_insert ( (const bson_t **) bsons, N_BSONS, continue_on_err, "Document 3 is too large", "{'nInserted': %d," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [{'index': 3}]}", continue_on_err ? 4 : 3); destroy_all (bsons, N_BSONS); } static void test_legacy_bulk_insert_oversized_middle (void) { _test_legacy_bulk_insert_oversized_middle (false); } static void test_legacy_bulk_insert_oversized_continue_middle (void) { _test_legacy_bulk_insert_oversized_middle (true); } static void _test_legacy_bulk_insert_oversized_first (bool continue_on_err) { enum { N_BSONS = 2 }; bson_t *bsons[N_BSONS]; bsons[0] = make_document (300); /* too big */ bsons[1] = make_document (100); _test_legacy_bulk_insert ( (const bson_t **) bsons, N_BSONS, continue_on_err, "Document 0 is too large", "{'nInserted': %d," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [{'index': 0}]}", continue_on_err ? 1 : 0); destroy_all (bsons, N_BSONS); } static void test_legacy_bulk_insert_oversized_first (void) { _test_legacy_bulk_insert_oversized_first (false); } static void test_legacy_bulk_insert_oversized_first_continue (void) { _test_legacy_bulk_insert_oversized_first (true); } static void _test_legacy_bulk_insert_oversized_last (bool continue_on_err) { enum { N_BSONS = 2 }; bson_t *bsons[N_BSONS]; bsons[0] = make_document (100); bsons[1] = make_document (300); /* too big */ _test_legacy_bulk_insert ( (const bson_t **) bsons, N_BSONS, continue_on_err, "Document 1 is too large", "{'nInserted': 1," " 'nMatched': 0," " 'nRemoved': 0," " 'nUpserted': 0," " 'writeErrors': [{'index': 1}]}"); destroy_all (bsons, N_BSONS); } static void test_legacy_bulk_insert_oversized_last (void) { _test_legacy_bulk_insert_oversized_last (false); } static void test_legacy_bulk_insert_oversized_last_continue (void) { _test_legacy_bulk_insert_oversized_last (true); } static void test_save (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; bson_context_t *context; bson_error_t error; bson_oid_t oid; unsigned i; bson_t b; client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_save"); ASSERT (collection); mongoc_collection_drop (collection, &error); context = bson_context_new(BSON_CONTEXT_NONE); ASSERT (context); for (i = 0; i < 10; i++) { bson_init(&b); bson_oid_init(&oid, context); bson_append_oid(&b, "_id", 3, &oid); bson_append_utf8(&b, "hello", 5, "/world", 5); ASSERT_OR_PRINT (mongoc_collection_save(collection, &b, NULL, &error), error); bson_destroy(&b); } bson_destroy (&b); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy(collection); mongoc_database_destroy(database); bson_context_destroy(context); mongoc_client_destroy(client); } static void test_regex (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_write_concern_t *wr; mongoc_client_t *client; bson_error_t error; int64_t count; bson_t q = BSON_INITIALIZER; bson_t *doc; client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_regex"); ASSERT (collection); wr = mongoc_write_concern_new (); mongoc_write_concern_set_journal (wr, true); doc = BCON_NEW ("hello", "/world"); ASSERT_OR_PRINT (mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, wr, &error), error); BSON_APPEND_REGEX (&q, "hello", "^/wo", "i"); count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &q, 0, 0, NULL, &error); ASSERT (count > 0); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_write_concern_destroy (wr); bson_destroy (&q); bson_destroy (doc); mongoc_collection_destroy (collection); mongoc_database_destroy(database); mongoc_client_destroy (client); } static void test_update (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; bson_context_t *context; bson_error_t error; bool r; bson_oid_t oid; unsigned i; bson_t b; bson_t q; bson_t u; bson_t set; client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_update"); ASSERT (collection); context = bson_context_new(BSON_CONTEXT_NONE); ASSERT (context); for (i = 0; i < 10; i++) { bson_init(&b); bson_oid_init(&oid, context); bson_append_oid(&b, "_id", 3, &oid); bson_append_utf8(&b, "utf8", 4, "utf8 string", 11); bson_append_int32(&b, "int32", 5, 1234); bson_append_int64(&b, "int64", 5, 12345678); bson_append_bool(&b, "bool", 4, 1); ASSERT_OR_PRINT (mongoc_collection_insert(collection, MONGOC_INSERT_NONE, &b, NULL, &error), error); bson_init(&q); bson_append_oid(&q, "_id", 3, &oid); bson_init(&u); bson_append_document_begin(&u, "$set", 4, &set); bson_append_utf8(&set, "utf8", 4, "updated", 7); bson_append_document_end(&u, &set); ASSERT_OR_PRINT (mongoc_collection_update(collection, MONGOC_UPDATE_NONE, &q, &u, NULL, &error), error); bson_destroy(&b); bson_destroy(&q); bson_destroy(&u); } bson_init(&q); bson_init(&u); BSON_APPEND_INT32 (&u, "abcd", 1); BSON_APPEND_INT32 (&u, "$hi", 1); r = mongoc_collection_update(collection, MONGOC_UPDATE_NONE, &q, &u, NULL, &error); ASSERT (!r); ASSERT (error.domain == MONGOC_ERROR_BSON); ASSERT (error.code == MONGOC_ERROR_BSON_INVALID); bson_destroy(&q); bson_destroy(&u); bson_init(&q); bson_init(&u); BSON_APPEND_INT32 (&u, "a.b.c.d", 1); r = mongoc_collection_update(collection, MONGOC_UPDATE_NONE, &q, &u, NULL, &error); ASSERT (!r); ASSERT (error.domain == MONGOC_ERROR_BSON); ASSERT (error.code == MONGOC_ERROR_BSON_INVALID); bson_destroy(&q); bson_destroy(&u); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy(collection); mongoc_database_destroy(database); bson_context_destroy(context); mongoc_client_destroy(client); } static void test_remove (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; bson_context_t *context; bson_error_t error; bool r; bson_oid_t oid; bson_t b; int i; client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_remove"); ASSERT (collection); context = bson_context_new(BSON_CONTEXT_NONE); ASSERT (context); for (i = 0; i < 100; i++) { bson_init(&b); bson_oid_init(&oid, context); bson_append_oid(&b, "_id", 3, &oid); bson_append_utf8(&b, "hello", 5, "world", 5); r = mongoc_collection_insert(collection, MONGOC_INSERT_NONE, &b, NULL, &error); if (!r) { MONGOC_WARNING("%s\n", error.message); } ASSERT (r); bson_destroy(&b); bson_init(&b); bson_append_oid(&b, "_id", 3, &oid); r = mongoc_collection_remove(collection, MONGOC_REMOVE_NONE, &b, NULL, &error); if (!r) { MONGOC_WARNING("%s\n", error.message); } ASSERT (r); bson_destroy(&b); } ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy(collection); mongoc_database_destroy(database); bson_context_destroy(context); mongoc_client_destroy(client); } static void test_index (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; mongoc_index_opt_t opt; bson_error_t error; bson_t keys; mongoc_index_opt_init(&opt); client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_index"); ASSERT (collection); bson_init(&keys); bson_append_int32(&keys, "hello", -1, 1); ASSERT_OR_PRINT (mongoc_collection_create_index(collection, &keys, &opt, &error), error); ASSERT_OR_PRINT (mongoc_collection_create_index(collection, &keys, &opt, &error), error); ASSERT_OR_PRINT (mongoc_collection_drop_index(collection, "hello_1", &error), error); bson_destroy(&keys); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy(collection); mongoc_database_destroy(database); mongoc_client_destroy(client); } static void test_index_compound (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; mongoc_index_opt_t opt; bson_error_t error; bson_t keys; mongoc_index_opt_init(&opt); client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_index_compound"); ASSERT (collection); bson_init(&keys); bson_append_int32(&keys, "hello", -1, 1); bson_append_int32(&keys, "world", -1, -1); ASSERT_OR_PRINT (mongoc_collection_create_index(collection, &keys, &opt, &error), error); ASSERT_OR_PRINT (mongoc_collection_create_index(collection, &keys, &opt, &error), error); ASSERT_OR_PRINT (mongoc_collection_drop_index(collection, "hello_1_world_-1", &error), error); bson_destroy(&keys); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy(collection); mongoc_database_destroy(database); mongoc_client_destroy(client); } static void test_index_geo (void) { mongoc_server_description_t *description; mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; mongoc_index_opt_t opt; mongoc_index_opt_geo_t geo_opt; bson_error_t error; bool r; bson_t keys; uint32_t id; mongoc_index_opt_init(&opt); mongoc_index_opt_geo_init(&geo_opt); client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_geo_index"); ASSERT (collection); /* Create a basic 2d index */ bson_init(&keys); BSON_APPEND_UTF8(&keys, "location", "2d"); ASSERT_OR_PRINT (mongoc_collection_create_index(collection, &keys, &opt, &error), error); ASSERT_OR_PRINT (mongoc_collection_drop_index(collection, "location_2d", &error), error); /* Create a 2d index with bells and whistles */ bson_init(&keys); BSON_APPEND_UTF8(&keys, "location", "2d"); geo_opt.twod_location_min = -123; geo_opt.twod_location_max = +123; geo_opt.twod_bits_precision = 30; opt.geo_options = &geo_opt; /* TODO this hack is needed for single-threaded tests */ id = client->topology->description.servers->items[0].id; description = mongoc_topology_server_by_id(client->topology, id, &error); ASSERT_OR_PRINT (description, error); if (description->max_wire_version > 0) { ASSERT_OR_PRINT (mongoc_collection_create_index(collection, &keys, &opt, &error), error); ASSERT_OR_PRINT (mongoc_collection_drop_index(collection, "location_2d", &error), error); } /* Create a Haystack index */ bson_init(&keys); BSON_APPEND_UTF8(&keys, "location", "geoHaystack"); BSON_APPEND_INT32(&keys, "category", 1); mongoc_index_opt_geo_init(&geo_opt); geo_opt.haystack_bucket_size = 5; opt.geo_options = &geo_opt; if (description->max_wire_version > 0) { ASSERT_OR_PRINT (mongoc_collection_create_index(collection, &keys, &opt, &error), error); r = mongoc_collection_drop_index(collection, "location_geoHaystack_category_1", &error); ASSERT_OR_PRINT (r, error); } mongoc_server_description_destroy(description); mongoc_collection_destroy(collection); mongoc_database_destroy(database); mongoc_client_destroy(client); } static char * storage_engine (mongoc_client_t *client) { bson_iter_t iter; bson_error_t error; bson_t cmd = BSON_INITIALIZER; bson_t reply; /* NOTE: this default will change eventually */ char *engine = bson_strdup("mmapv1"); BSON_APPEND_INT32 (&cmd, "getCmdLineOpts", 1); ASSERT_OR_PRINT (mongoc_client_command_simple(client, "admin", &cmd, NULL, &reply, &error), error); if (bson_iter_init_find (&iter, &reply, "parsed.storage.engine")) { engine = bson_strdup(bson_iter_utf8(&iter, NULL)); } bson_destroy (&reply); bson_destroy (&cmd); return engine; } static void test_index_storage (void) { mongoc_collection_t *collection = NULL; mongoc_database_t *database = NULL; mongoc_client_t *client = NULL; mongoc_index_opt_t opt; mongoc_index_opt_wt_t wt_opt; bson_error_t error; bson_t keys; char *engine = NULL; client = test_framework_client_new (); ASSERT (client); /* Skip unless we are on WT */ engine = storage_engine(client); if (strcmp("wiredTiger", engine) != 0) { goto cleanup; } mongoc_index_opt_init (&opt); mongoc_index_opt_wt_init (&wt_opt); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_storage_index"); ASSERT (collection); /* Create a simple index */ bson_init (&keys); bson_append_int32 (&keys, "hello", -1, 1); /* Add storage option to the index */ wt_opt.base.type = MONGOC_INDEX_STORAGE_OPT_WIREDTIGER; wt_opt.config_str = "block_compressor=zlib"; opt.storage_options = (mongoc_index_opt_storage_t *)&wt_opt; ASSERT_OR_PRINT (mongoc_collection_create_index (collection, &keys, &opt, &error), error); cleanup: if (engine) bson_free (engine); if (collection) mongoc_collection_destroy (collection); if (database) mongoc_database_destroy (database); if (client) mongoc_client_destroy (client); } static void test_count (void) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; int64_t count; bson_t b; client = test_framework_client_new (); ASSERT (client); collection = mongoc_client_get_collection(client, "test", "test"); ASSERT (collection); bson_init(&b); count = mongoc_collection_count(collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); if (count == -1) { MONGOC_WARNING("%s\n", error.message); } ASSERT (count != -1); mongoc_collection_destroy(collection); mongoc_client_destroy(client); } static void test_count_read_concern (void) { mongoc_collection_t *collection; mongoc_client_t *client; mongoc_read_concern_t *rc; mock_server_t *server; request_t *request; bson_error_t error; future_t *future; int64_t count; bson_t b; /* wire protocol version 4 */ server = mock_server_with_autoismaster (WIRE_VERSION_READ_CONCERN); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test"); ASSERT (collection); bson_init(&b); future = future_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); request = mock_server_receives_command ( server, "test", MONGOC_QUERY_SLAVE_OK, "{ 'count' : 'test', 'query' : { } }"); mock_server_replies_simple (request, "{ 'n' : 42, 'ok' : 1 } "); count = future_get_int64_t (future); ASSERT_OR_PRINT (count == 42, error); /* readConcern: { level: majority } */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_MAJORITY); mongoc_collection_set_read_concern (collection, rc); bson_init(&b); future = future_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); request = mock_server_receives_command ( server, "test", MONGOC_QUERY_SLAVE_OK, "{ 'count' : 'test', 'query' : { }, 'readConcern': {'level': 'majority'}}"); mock_server_replies_simple (request, "{ 'n' : 43, 'ok' : 1 } "); count = future_get_int64_t (future); ASSERT_OR_PRINT (count == 43, error); mongoc_read_concern_destroy (rc); /* readConcern: { level: local } */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_LOCAL); mongoc_collection_set_read_concern (collection, rc); bson_init(&b); future = future_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); request = mock_server_receives_command ( server, "test", MONGOC_QUERY_SLAVE_OK, "{ 'count' : 'test', 'query' : { }, 'readConcern': {'level': 'local'}}"); mock_server_replies_simple (request, "{ 'n' : 44, 'ok' : 1 } "); count = future_get_int64_t (future); ASSERT_OR_PRINT (count == 44, error); mongoc_read_concern_destroy (rc); /* readConcern: { level: futureCompatible } */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, "futureCompatible"); mongoc_collection_set_read_concern (collection, rc); bson_init(&b); future = future_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); request = mock_server_receives_command ( server, "test", MONGOC_QUERY_SLAVE_OK, "{ 'count' : 'test', 'query' : { }, 'readConcern': {'level': 'futureCompatible'}}"); mock_server_replies_simple (request, "{ 'n' : 45, 'ok' : 1 } "); count = future_get_int64_t (future); ASSERT_OR_PRINT (count == 45, error); mongoc_read_concern_destroy (rc); /* Setting readConcern to NULL should not send readConcern */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, NULL); mongoc_collection_set_read_concern (collection, rc); bson_init(&b); future = future_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); request = mock_server_receives_command ( server, "test", MONGOC_QUERY_SLAVE_OK, "{ 'count' : 'test', 'query' : { }, 'readConcern': { '$exists': false }}"); mock_server_replies_simple (request, "{ 'n' : 46, 'ok' : 1 } "); count = future_get_int64_t (future); ASSERT_OR_PRINT (count == 46, error); mongoc_read_concern_destroy (rc); /* Fresh read_concern should not send readConcern */ rc = mongoc_read_concern_new (); mongoc_collection_set_read_concern (collection, rc); bson_init(&b); future = future_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); request = mock_server_receives_command ( server, "test", MONGOC_QUERY_SLAVE_OK, "{ 'count' : 'test', 'query' : { }, 'readConcern': { '$exists': false }}"); mock_server_replies_simple (request, "{ 'n' : 47, 'ok' : 1 } "); count = future_get_int64_t (future); ASSERT_OR_PRINT (count == 47, error); mongoc_read_concern_destroy (rc); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } static void _test_count_read_concern_live (bool supports_read_concern) { mongoc_collection_t *collection; mongoc_client_t *client; mongoc_read_concern_t *rc; bson_error_t error; int64_t count; bson_t b; client = test_framework_client_new (); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test"); ASSERT (collection); mongoc_collection_drop (collection, &error); bson_init(&b); count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); ASSERT_OR_PRINT (count == 0, error); /* Setting readConcern to NULL should not send readConcern */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, NULL); mongoc_collection_set_read_concern (collection, rc); bson_init(&b); count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); ASSERT_OR_PRINT (count == 0, error); mongoc_read_concern_destroy (rc); /* readConcern: { level: local } should raise error pre 3.2 */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_LOCAL); mongoc_collection_set_read_concern (collection, rc); bson_init(&b); count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); if (supports_read_concern) { ASSERT_OR_PRINT (count == 0, error); } else { ASSERT_ERROR_CONTAINS(error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support readConcern") } mongoc_read_concern_destroy (rc); /* readConcern: { level: majority } should raise error pre 3.2 */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_MAJORITY); mongoc_collection_set_read_concern (collection, rc); bson_init(&b); count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &b, 0, 0, NULL, &error); bson_destroy(&b); if (supports_read_concern) { ASSERT_OR_PRINT (count == 0, error); } else { ASSERT_ERROR_CONTAINS(error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support readConcern") } mongoc_read_concern_destroy (rc); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } int mongod_supports_majority_read_concern (void) { return test_framework_getenv_bool ("MONGOC_ENABLE_MAJORITY_READ_CONCERN"); } static void test_count_read_concern_live (void *context) { if (test_framework_max_wire_version_at_least (WIRE_VERSION_READ_CONCERN)) { _test_count_read_concern_live (true); } else { _test_count_read_concern_live (false); } } static void test_count_with_opts (void) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; int64_t count; bson_t b; bson_t opts; client = test_framework_client_new (); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test"); ASSERT (collection); bson_init (&opts); BSON_APPEND_UTF8 (&opts, "hint", "_id_"); bson_init (&b); count = mongoc_collection_count_with_opts (collection, MONGOC_QUERY_NONE, &b, 0, 0, &opts, NULL, &error); bson_destroy (&b); bson_destroy (&opts); if (count == -1) { MONGOC_WARNING ("%s\n", error.message); } ASSERT (count != -1); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_drop (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; bson_error_t error; bson_t *doc; client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_drop"); ASSERT (collection); doc = BCON_NEW("hello", "world"); ASSERT_OR_PRINT (mongoc_collection_insert(collection, MONGOC_INSERT_NONE, doc, NULL, &error), error); bson_destroy (doc); ASSERT_OR_PRINT (mongoc_collection_drop(collection, &error), error); ASSERT (!mongoc_collection_drop(collection, &error)); mongoc_collection_destroy(collection); mongoc_database_destroy(database); mongoc_client_destroy(client); } static void test_aggregate_bypass (void *context) { mongoc_collection_t *data_collection; mongoc_collection_t *out_collection; mongoc_bulk_operation_t *bulk; mongoc_database_t *database; mongoc_client_t *client; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; bson_t *pipeline; bson_t *options; char *collname; char *dbname; bson_t reply; bool r; int i; client = test_framework_client_new (); assert (client); dbname = gen_collection_name ("dbtest"); collname = gen_collection_name ("data"); database = mongoc_client_get_database (client, dbname); data_collection = mongoc_database_get_collection (database, collname); bson_free (collname); collname = gen_collection_name ("bypass"); options = tmp_bson ("{'validator': {'number': {'$gte': 5}}, 'validationAction': 'error'}"); ASSERT_OR_PRINT (mongoc_database_create_collection (database, collname, options, &error), error); out_collection = mongoc_database_get_collection (database, collname); bson_free (dbname); bson_free (collname); /* Generate some example data */ bulk = mongoc_collection_create_bulk_operation(data_collection, true, NULL); for (i = 0; i < 3; i++) { bson_t *document = tmp_bson (bson_strdup_printf ("{'number': 3, 'high': %d }", i)); mongoc_bulk_operation_insert (bulk, document); } r = mongoc_bulk_operation_execute (bulk, &reply, &error); ASSERT_OR_PRINT(r, error); mongoc_bulk_operation_destroy (bulk); /* }}} */ pipeline = tmp_bson (bson_strdup_printf ("[{'$out': '%s'}]", out_collection->collection)); cursor = mongoc_collection_aggregate(data_collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL); ASSERT (cursor); r = mongoc_cursor_next (cursor, &doc); ASSERT (!r); ASSERT (mongoc_cursor_error (cursor, &error)); ASSERT_STARTSWITH (error.message, "insert for $out failed"); options = tmp_bson("{'bypassDocumentValidation': true}"); cursor = mongoc_collection_aggregate(data_collection, MONGOC_QUERY_NONE, pipeline, options, NULL); ASSERT (cursor); ASSERT (!mongoc_cursor_error (cursor, &error)); ASSERT_OR_PRINT (mongoc_collection_drop(data_collection, &error), error); ASSERT_OR_PRINT (mongoc_collection_drop(out_collection, &error), error); mongoc_collection_destroy(data_collection); mongoc_collection_destroy(out_collection); mongoc_database_destroy(database); mongoc_client_destroy(client); } static void test_aggregate (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; mongoc_cursor_t *cursor; const bson_t *doc; bson_error_t error; bool did_alternate = false; bool r; bson_t opts; bson_t *pipeline; bson_t *broken_pipeline; bson_t *b; bson_iter_t iter; int i, j; client = test_framework_client_new (); ASSERT (client); database = get_test_database (client); ASSERT (database); collection = get_test_collection (client, "test_aggregate"); ASSERT (collection); pipeline = BCON_NEW ("pipeline", "[", "{", "$match", "{", "hello", BCON_UTF8 ("world"), "}", "}", "]"); broken_pipeline = BCON_NEW ("pipeline", "[", "{", "$asdf", "{", "foo", BCON_UTF8 ("bar"), "}", "}", "]"); b = BCON_NEW ("hello", BCON_UTF8 ("world")); again: mongoc_collection_drop(collection, &error); for (i = 0; i < 2; i++) { ASSERT_OR_PRINT (mongoc_collection_insert( collection, MONGOC_INSERT_NONE, b, NULL, &error), error); } cursor = mongoc_collection_aggregate (collection, MONGOC_QUERY_NONE, broken_pipeline, NULL, NULL); ASSERT (cursor); r = mongoc_cursor_next (cursor, &doc); ASSERT (!r); ASSERT (mongoc_cursor_error (cursor, &error)); ASSERT (error.code == 16436); for (i = 0; i < 2; i++) { if (i % 2 == 0) { cursor = mongoc_collection_aggregate(collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL); ASSERT (cursor); } else { bson_init (&opts); /* servers < 2.6 error is passed allowDiskUse */ if (test_framework_max_wire_version_at_least (2)) { BSON_APPEND_BOOL (&opts, "allowDiskUse", true); } /* this is ok, the driver silently omits batchSize if server < 2.6 */ BSON_APPEND_INT32 (&opts, "batchSize", 10); cursor = mongoc_collection_aggregate(collection, MONGOC_QUERY_NONE, pipeline, &opts, NULL); ASSERT (cursor); bson_destroy (&opts); } for (j = 0; j < 2; j++) { r = mongoc_cursor_next(cursor, &doc); if (mongoc_cursor_error(cursor, &error)) { fprintf (stderr, "[%d.%d] %s", error.domain, error.code, error.message); abort (); } ASSERT (r); ASSERT (doc); ASSERT (bson_iter_init_find (&iter, doc, "hello") && BSON_ITER_HOLDS_UTF8 (&iter)); } r = mongoc_cursor_next(cursor, &doc); if (mongoc_cursor_error(cursor, &error)) { fprintf (stderr, "%s", error.message); abort (); } ASSERT (!r); ASSERT (!doc); mongoc_cursor_destroy(cursor); } if (!did_alternate) { did_alternate = true; bson_destroy (pipeline); pipeline = BCON_NEW ("0", "{", "$match", "{", "hello", BCON_UTF8 ("world"), "}", "}"); goto again; } ASSERT_OR_PRINT (mongoc_collection_drop(collection, &error), error); mongoc_collection_destroy(collection); mongoc_database_destroy(database); mongoc_client_destroy(client); bson_destroy(b); bson_destroy(pipeline); bson_destroy (broken_pipeline); } static void test_aggregate_large (void) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_bulk_operation_t *bulk; bson_iter_t iter; int32_t i; uint32_t hint; mongoc_cursor_t *cursor; bson_t *inserted_doc; bson_error_t error; bson_t *pipeline; const bson_t *doc; client = test_framework_client_new (); ASSERT (client); collection = get_test_collection (client, "test_aggregate_large"); ASSERT (collection); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); /* ensure a few batches */ inserted_doc = tmp_bson ("{'_id': 0}"); for (i = 0; i < 2000; i++) { bson_iter_init_find (&iter, inserted_doc, "_id"); bson_iter_overwrite_int32 (&iter, i); mongoc_bulk_operation_insert (bulk, inserted_doc); } hint = mongoc_bulk_operation_execute (bulk, NULL, &error); ASSERT_OR_PRINT (hint > 0, error); pipeline = tmp_bson ("[{'$sort': {'_id': 1}}]"); cursor = mongoc_collection_aggregate (collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL); ASSERT (cursor); i = 0; while (mongoc_cursor_next (cursor, &doc)) { ASSERT (bson_iter_init_find (&iter, doc, "_id")); ASSERT_CMPINT (i, ==, bson_iter_int32 (&iter)); i++; } ASSERT_OR_PRINT (!mongoc_cursor_error (cursor, &error), error); ASSERT_CMPINT (i, ==, 2000); mongoc_bulk_operation_destroy (bulk); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } typedef struct { bool with_batch_size; bool with_options; } test_aggregate_context_t; static const char * options_json (test_aggregate_context_t *c) { if (c->with_batch_size && c->with_options) { return "{'foo': 1, 'batchSize': 11}"; } else if (c->with_batch_size) { return "{'batchSize': 11}"; } else if (c->with_options) { return "{'foo': 1}"; } else { return "{}"; } } static void test_aggregate_legacy (void *data) { test_aggregate_context_t *context = (test_aggregate_context_t *) data; mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; future_t *future; request_t *request; mongoc_cursor_t *cursor; const bson_t *doc; /* wire protocol version 0 */ server = mock_server_with_autoismaster (0); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); cursor = mongoc_collection_aggregate ( collection, MONGOC_QUERY_NONE, tmp_bson ("[{'a': 1}]"), tmp_bson (options_json (context)), NULL); future = future_cursor_next (cursor, &doc); /* no "cursor" argument */ request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{'aggregate': 'collection'," " 'pipeline': [{'a': 1}]}," " 'cursor': {'$exists': false} %s", context->with_options ? ", 'foo': 1" : ""); mock_server_replies_simple (request, "{'ok': 1, 'result': [{'_id': 123}]}"); assert (future_get_bool (future)); ASSERT_MATCH (doc, "{'_id': 123}"); /* cursor is completed */ assert (!mongoc_cursor_next (cursor, &doc)); mongoc_cursor_destroy (cursor); request_destroy (request); future_destroy (future); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } static void test_aggregate_modern (void *data) { test_aggregate_context_t *context = (test_aggregate_context_t *) data; mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; future_t *future; request_t *request; mongoc_cursor_t *cursor; const bson_t *doc; /* wire protocol version 1 */ server = mock_server_with_autoismaster (1); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); cursor = mongoc_collection_aggregate ( collection, MONGOC_QUERY_NONE, tmp_bson ("[{'a': 1}]"), tmp_bson (options_json (context)), NULL); ASSERT (cursor); future = future_cursor_next (cursor, &doc); /* "cursor" argument always sent if wire version >= 1 */ request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{'aggregate': 'collection'," " 'pipeline': [{'a': 1}]," " 'cursor': %s %s}", context->with_batch_size ? "{'batchSize': 11}" : "{'$empty': true}", context->with_options ? ", 'foo': 1" : ""); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'db.collection'," " 'firstBatch': [{'_id': 123}]" "}}"); ASSERT (future_get_bool (future)); ASSERT_MATCH (doc, "{'_id': 123}"); /* cursor is completed */ assert (!mongoc_cursor_next (cursor, &doc)); mongoc_cursor_destroy (cursor); request_destroy (request); future_destroy (future); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } static void test_validate (void) { mongoc_collection_t *collection; mongoc_client_t *client; bson_iter_t iter; bson_error_t error; bson_t doc = BSON_INITIALIZER; bson_t opts = BSON_INITIALIZER; bson_t reply; bool r; client = test_framework_client_new (); ASSERT (client); collection = get_test_collection (client, "test_validate"); ASSERT (collection); ASSERT_OR_PRINT (mongoc_collection_insert(collection, MONGOC_INSERT_NONE, &doc, NULL, &error), error); BSON_APPEND_BOOL (&opts, "full", true); ASSERT_OR_PRINT (mongoc_collection_validate (collection, &opts, &reply, &error), error); assert (bson_iter_init_find (&iter, &reply, "valid")); bson_destroy (&reply); bson_reinit (&opts); BSON_APPEND_UTF8 (&opts, "full", "bad_value"); r = mongoc_collection_validate (collection, &opts, &reply, &error); assert (!r); assert (error.domain == MONGOC_ERROR_BSON); assert (error.code == MONGOC_ERROR_BSON_INVALID); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&doc); bson_destroy (&opts); } static void test_rename (void) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; bson_t doc = BSON_INITIALIZER; client = test_framework_client_new (); ASSERT (client); collection = get_test_collection (client, "test_rename"); ASSERT (collection); ASSERT_OR_PRINT (mongoc_collection_insert ( collection, MONGOC_INSERT_NONE, &doc, NULL, &error), error); ASSERT_OR_PRINT (mongoc_collection_rename ( collection, "test", "test_rename_2", false, &error), error); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&doc); } static void test_stats (void) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; bson_iter_t iter; bson_t stats; bson_t doc = BSON_INITIALIZER; client = test_framework_client_new (); ASSERT (client); collection = get_test_collection (client, "test_stats"); ASSERT (collection); ASSERT_OR_PRINT (mongoc_collection_insert ( collection, MONGOC_INSERT_NONE, &doc, NULL, &error), error); ASSERT_OR_PRINT (mongoc_collection_stats ( collection, NULL, &stats, &error), error); assert (bson_iter_init_find (&iter, &stats, "ns")); assert (bson_iter_init_find (&iter, &stats, "count")); assert (bson_iter_as_int64 (&iter) >= 1); bson_destroy (&stats); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&doc); } static void test_find_and_modify_write_concern (int wire_version) { mongoc_collection_t *collection; mongoc_client_t *client; mock_server_t *server; request_t *request; future_t *future; bson_error_t error; bson_t *update; bson_t doc = BSON_INITIALIZER; bson_t reply; mongoc_write_concern_t *write_concern; server = mock_server_new (); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test_find_and_modify"); auto_ismaster (server, wire_version, /* max_wire_version */ 48000000, /* max_message_size */ 16777216, /* max_bson_size */ 1000); /* max_write_batch_size */ BSON_APPEND_INT32 (&doc, "superduper", 77889); update = BCON_NEW ("$set", "{", "superduper", BCON_INT32 (1234), "}"); write_concern = mongoc_write_concern_new (); mongoc_write_concern_set_w (write_concern, 42); mongoc_collection_set_write_concern (collection, write_concern); future = future_collection_find_and_modify (collection, &doc, NULL, update, NULL, false, false, true, &reply, &error); if (wire_version >= 4) { request = mock_server_receives_command (server, "test", MONGOC_QUERY_NONE, "{ 'findAndModify' : 'test_find_and_modify', " "'query' : { 'superduper' : 77889 }," "'update' : { '$set' : { 'superduper' : 1234 } }," "'new' : true," "'writeConcern' : { 'w' : 42 } }"); } else { request = mock_server_receives_command (server, "test", MONGOC_QUERY_NONE, "{ 'findAndModify' : 'test_find_and_modify', " "'query' : { 'superduper' : 77889 }," "'update' : { '$set' : { 'superduper' : 1234 } }," "'new' : true }"); } mock_server_replies_simple (request, "{ 'value' : null, 'ok' : 1 }"); ASSERT_OR_PRINT (future_get_bool (future), error); future_destroy (future); bson_destroy (&reply); bson_destroy (update); mongoc_write_concern_destroy (write_concern); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&doc); } static void test_find_and_modify_write_concern_wire_32 (void) { test_find_and_modify_write_concern (4); } static void test_find_and_modify_write_concern_wire_pre_32 (void) { test_find_and_modify_write_concern (2); } static void test_find_and_modify (void) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; bson_iter_t iter; bson_iter_t citer; bson_t *update; bson_t doc = BSON_INITIALIZER; bson_t reply; client = test_framework_client_new (); ASSERT (client); collection = get_test_collection (client, "test_find_and_modify"); ASSERT (collection); BSON_APPEND_INT32 (&doc, "superduper", 77889); ASSERT_OR_PRINT (mongoc_collection_insert ( collection, MONGOC_INSERT_NONE, &doc, NULL, &error), error); update = BCON_NEW ("$set", "{", "superduper", BCON_INT32 (1234), "}"); ASSERT_OR_PRINT (mongoc_collection_find_and_modify (collection, &doc, NULL, update, NULL, false, false, true, &reply, &error), error); assert (bson_iter_init_find (&iter, &reply, "value")); assert (BSON_ITER_HOLDS_DOCUMENT (&iter)); assert (bson_iter_recurse (&iter, &citer)); assert (bson_iter_find (&citer, "superduper")); assert (BSON_ITER_HOLDS_INT32 (&citer)); assert (bson_iter_int32 (&citer) == 1234); assert (bson_iter_init_find (&iter, &reply, "lastErrorObject")); assert (BSON_ITER_HOLDS_DOCUMENT (&iter)); assert (bson_iter_recurse (&iter, &citer)); assert (bson_iter_find (&citer, "updatedExisting")); assert (BSON_ITER_HOLDS_BOOL (&citer)); assert (bson_iter_bool (&citer)); bson_destroy (&reply); bson_destroy (update); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&doc); } static void test_large_return (void) { mongoc_collection_t *collection; mongoc_client_t *client; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc = NULL; bson_oid_t oid; bson_t insert_doc = BSON_INITIALIZER; bson_t query = BSON_INITIALIZER; size_t len; char *str; bool r; client = test_framework_client_new (); ASSERT (client); collection = get_test_collection (client, "test_large_return"); ASSERT (collection); len = 1024 * 1024 * 4; str = (char *)bson_malloc (len); memset (str, (int)' ', len); str [len - 1] = '\0'; bson_oid_init (&oid, NULL); BSON_APPEND_OID (&insert_doc, "_id", &oid); BSON_APPEND_UTF8 (&insert_doc, "big", str); ASSERT_OR_PRINT (mongoc_collection_insert ( collection, MONGOC_INSERT_NONE, &insert_doc, NULL, &error), error); bson_destroy (&insert_doc); BSON_APPEND_OID (&query, "_id", &oid); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, NULL); assert (cursor); bson_destroy (&query); ASSERT_OR_PRINT (mongoc_cursor_next (cursor, &doc), error); assert (doc); r = mongoc_cursor_next (cursor, &doc); assert (!r); mongoc_cursor_destroy (cursor); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_free (str); } static void test_many_return (void) { enum { N_BSONS = 5000 }; mongoc_collection_t *collection; mongoc_client_t *client; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc = NULL; bson_oid_t oid; bson_t query = BSON_INITIALIZER; bson_t *docs[N_BSONS]; bool r; int i; client = test_framework_client_new (); ASSERT (client); collection = get_test_collection (client, "test_many_return"); ASSERT (collection); for (i = 0; i < N_BSONS; i++) { docs [i] = bson_new (); bson_oid_init (&oid, NULL); BSON_APPEND_OID (docs [i], "_id", &oid); } BEGIN_IGNORE_DEPRECATIONS; ASSERT_OR_PRINT (mongoc_collection_insert_bulk ( collection, MONGOC_INSERT_NONE, (const bson_t **)docs, (uint32_t) N_BSONS, NULL, &error), error); END_IGNORE_DEPRECATIONS; cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 6000, &query, NULL, NULL); assert (cursor); bson_destroy (&query); i = 0; while (mongoc_cursor_next (cursor, &doc)) { assert (doc); i++; } assert (i == N_BSONS); r = mongoc_cursor_next (cursor, &doc); assert (!r); mongoc_cursor_destroy (cursor); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); destroy_all (docs, N_BSONS); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } /* use a mock server to test the "limit" parameter */ static void test_find_limit (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; future_t *future; request_t *request; const bson_t *doc; server = mock_server_with_autoismaster (0); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "test", "test"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0 /* skip */, 2 /* limit */, 0 /* batch_size */, tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); request = mock_server_receives_query (server, "test.test", MONGOC_QUERY_SLAVE_OK, 0 /* skip */, 2 /* n_return */, "{}", NULL); mock_server_replies_simple (request, "{}"); assert (future_get_bool (future)); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mock_server_destroy (server); } /* use a mock server to test the "batch_size" parameter */ static void test_find_batch_size (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; future_t *future; request_t *request; const bson_t *doc; server = mock_server_with_autoismaster (0); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "test", "test"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0 /* skip */, 0 /* limit */, 2 /* batch_size */, tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); request = mock_server_receives_query (server, "test.test", MONGOC_QUERY_SLAVE_OK, 0 /* skip */, 2 /* n_return */, "{}", NULL); mock_server_replies_simple (request, "{}"); assert (future_get_bool (future)); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mock_server_destroy (server); } static void test_command_fq (void *context) { mongoc_client_t *client; mongoc_cursor_t *cursor; const bson_t *doc = NULL; bson_iter_t iter; bson_t *cmd; bool r; client = test_framework_client_new (); ASSERT (client); cmd = tmp_bson ("{ 'dbstats': 1}"); cursor = mongoc_client_command (client, "sometest.$cmd", MONGOC_QUERY_SLAVE_OK, 0, -1, 0, cmd, NULL, NULL); r = mongoc_cursor_next (cursor, &doc); assert (r); if (bson_iter_init_find (&iter, doc, "db") && BSON_ITER_HOLDS_UTF8 (&iter)) { ASSERT_CMPSTR (bson_iter_utf8 (&iter, NULL), "sometest"); } else { fprintf(stderr, "dbstats didn't return 'db' key?"); abort(); } r = mongoc_cursor_next (cursor, &doc); assert (!r); mongoc_cursor_destroy (cursor); mongoc_client_destroy (client); } static void test_get_index_info (void) { mongoc_collection_t *collection; mongoc_client_t *client; mongoc_index_opt_t opt1; mongoc_index_opt_t opt2; bson_error_t error = { 0 }; mongoc_cursor_t *cursor; const bson_t *indexinfo; bson_t indexkey1; bson_t indexkey2; bson_t dummy = BSON_INITIALIZER; bson_iter_t idx_spec_iter; bson_iter_t idx_spec_iter_copy; bool r; const char *cur_idx_name; char *idx1_name = NULL; char *idx2_name = NULL; const char *id_idx_name = "_id_"; int num_idxs = 0; client = test_framework_client_new (); ASSERT (client); collection = get_test_collection (client, "test_get_index_info"); ASSERT (collection); /* * Try it on a collection that doesn't exist. */ cursor = mongoc_collection_find_indexes (collection, &error); ASSERT (cursor); ASSERT (!error.domain); ASSERT (!error.code); ASSERT (!mongoc_cursor_next( cursor, &indexinfo )); mongoc_cursor_destroy (cursor); /* insert a dummy document so that the collection actually exists */ r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, &dummy, NULL, &error); ASSERT (r); /* Try it on a collection with no secondary indexes. * We should just get back the index on _id. */ cursor = mongoc_collection_find_indexes (collection, &error); ASSERT (cursor); ASSERT (!error.domain); ASSERT (!error.code); while (mongoc_cursor_next (cursor, &indexinfo)) { if (bson_iter_init (&idx_spec_iter, indexinfo) && bson_iter_find (&idx_spec_iter, "name") && BSON_ITER_HOLDS_UTF8 (&idx_spec_iter) && (cur_idx_name = bson_iter_utf8 (&idx_spec_iter, NULL))) { assert (0 == strcmp (cur_idx_name, id_idx_name)); ++num_idxs; } else { assert (false); } } assert (1 == num_idxs); mongoc_cursor_destroy (cursor); num_idxs = 0; indexinfo = NULL; bson_init (&indexkey1); BSON_APPEND_INT32 (&indexkey1, "raspberry", 1); idx1_name = mongoc_collection_keys_to_index_string (&indexkey1); mongoc_index_opt_init (&opt1); opt1.background = true; ASSERT_OR_PRINT (mongoc_collection_create_index ( collection, &indexkey1, &opt1, &error), error); bson_init (&indexkey2); BSON_APPEND_INT32 (&indexkey2, "snozzberry", 1); idx2_name = mongoc_collection_keys_to_index_string (&indexkey2); mongoc_index_opt_init (&opt2); opt2.unique = true; ASSERT_OR_PRINT (mongoc_collection_create_index ( collection, &indexkey2, &opt2, &error), error); /* * Now we try again after creating two indexes. */ cursor = mongoc_collection_find_indexes (collection, &error); ASSERT (cursor); ASSERT (!error.domain); ASSERT (!error.code); while (mongoc_cursor_next (cursor, &indexinfo)) { if (bson_iter_init (&idx_spec_iter, indexinfo) && bson_iter_find (&idx_spec_iter, "name") && BSON_ITER_HOLDS_UTF8 (&idx_spec_iter) && (cur_idx_name = bson_iter_utf8 (&idx_spec_iter, NULL))) { if (0 == strcmp (cur_idx_name, idx1_name)) { /* need to use the copy of the iter since idx_spec_iter may have gone * past the key we want */ ASSERT (bson_iter_init_find (&idx_spec_iter_copy, indexinfo, "background")); ASSERT (BSON_ITER_HOLDS_BOOL (&idx_spec_iter_copy)); ASSERT (bson_iter_bool (&idx_spec_iter_copy)); } else if (0 == strcmp (cur_idx_name, idx2_name)) { ASSERT (bson_iter_init_find (&idx_spec_iter_copy, indexinfo, "unique")); ASSERT (BSON_ITER_HOLDS_BOOL (&idx_spec_iter_copy)); ASSERT (bson_iter_bool (&idx_spec_iter_copy)); } else { ASSERT ((0 == strcmp (cur_idx_name, id_idx_name))); } ++num_idxs; } else { assert (false); } } assert (3 == num_idxs); mongoc_cursor_destroy (cursor); bson_free (idx1_name); bson_free (idx2_name); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_aggregate_install (TestSuite *suite) { static test_aggregate_context_t test_aggregate_contexts[2][2][2]; int wire_version, with_batch_size, with_options; char *legacy_or_modern; TestFuncWC func; char *name; test_aggregate_context_t *context; for (wire_version = 0; wire_version < 2; wire_version++) { for (with_batch_size = 0; with_batch_size < 2; with_batch_size++) { for (with_options = 0; with_options < 2; with_options++) { legacy_or_modern = wire_version ? "legacy" : "modern"; func = wire_version ? test_aggregate_legacy : test_aggregate_modern; context = &test_aggregate_contexts [wire_version][with_batch_size][with_options]; context->with_batch_size = (bool) with_batch_size; context->with_options = (bool) with_options; name = bson_strdup_printf ( "/Collection/aggregate/%s/%s/%s", legacy_or_modern, context->with_batch_size ? "batch_size" : "no_batch_size", context->with_options ? "with_options" : "no_options"); TestSuite_AddWC (suite, name, func, NULL, (void *) context); bson_free (name); } } } } static void test_find_read_concern (void) { mock_server_t *server; mongoc_client_t *client; mongoc_read_concern_t *rc; mongoc_collection_t *collection; mongoc_cursor_t *cursor; future_t *future; request_t *request; const bson_t *doc; server = mock_server_with_autoismaster (WIRE_VERSION_READ_CONCERN); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "test", "test"); /* No read_concern set */ cursor = mongoc_collection_find (collection, MONGOC_QUERY_SLAVE_OK, 0 /* skip */, 0 /* limit */, 0 /* batch_size */, tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command (server, "test", MONGOC_QUERY_SLAVE_OK, "{'find' : 'test', 'filter' : { } }"); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'test.test'," " 'firstBatch': [{'_id': 123}]}}"); ASSERT (future_get_bool (future)); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); /* readConcernLevel = local */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_LOCAL); mongoc_collection_set_read_concern (collection, rc); cursor = mongoc_collection_find (collection, MONGOC_QUERY_SLAVE_OK, 0 /* skip */, 0 /* limit */, 0 /* batch_size */, tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command (server, "test", MONGOC_QUERY_SLAVE_OK, "{" " 'find' : 'test'," " 'filter' : { }," " 'readConcern': {" " 'level': 'local'" " }" "}"); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'test.test'," " 'firstBatch': [{'_id': 123}]}}"); ASSERT (future_get_bool (future)); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); /* readConcernLevel = random */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, "random"); mongoc_collection_set_read_concern (collection, rc); cursor = mongoc_collection_find (collection, MONGOC_QUERY_SLAVE_OK, 0 /* skip */, 0 /* limit */, 0 /* batch_size */, tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command (server, "test", MONGOC_QUERY_SLAVE_OK, "{" " 'find' : 'test'," " 'filter' : { }," " 'readConcern': {" " 'level': 'random'" " }" "}"); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'test.test'," " 'firstBatch': [{'_id': 123}]}}"); ASSERT (future_get_bool (future)); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); /* empty readConcernLevel doesn't send anything */ rc = mongoc_read_concern_new (); mongoc_collection_set_read_concern (collection, rc); cursor = mongoc_collection_find (collection, MONGOC_QUERY_SLAVE_OK, 0 /* skip */, 0 /* limit */, 0 /* batch_size */, tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command (server, "test", MONGOC_QUERY_SLAVE_OK, "{" " 'find' : 'test'," " 'filter' : { }," " 'readConcern': { '$exists': false }" "}"); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'test.test'," " 'firstBatch': [{'_id': 123}]}}"); ASSERT (future_get_bool (future)); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); /* readConcernLevel = NULL doesn't send anything */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, NULL); mongoc_collection_set_read_concern (collection, rc); cursor = mongoc_collection_find (collection, MONGOC_QUERY_SLAVE_OK, 0 /* skip */, 0 /* limit */, 0 /* batch_size */, tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command (server, "test", MONGOC_QUERY_SLAVE_OK, "{" " 'find' : 'test'," " 'filter' : { }," " 'readConcern': { '$exists': false }" "}"); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'test.test'," " 'firstBatch': [{'_id': 123}]}}"); ASSERT (future_get_bool (future)); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mock_server_destroy (server); } static void test_aggregate_read_concern (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_read_concern_t *rc; future_t *future; request_t *request; mongoc_cursor_t *cursor; const bson_t *doc; server = mock_server_with_autoismaster (WIRE_VERSION_READ_CONCERN); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); /* No readConcern */ cursor = mongoc_collection_aggregate ( collection, MONGOC_QUERY_NONE, tmp_bson ("[{'a': 1}]"), NULL, NULL); ASSERT (cursor); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{" " 'aggregate' : 'collection'," " 'pipeline' : [{" " 'a' : 1" " }]," " 'cursor' : { }," " 'readConcern': { '$exists': false }" "}" ); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'db.collection'," " 'firstBatch': [{'_id': 123}]" "}}"); ASSERT (future_get_bool (future)); ASSERT_MATCH (doc, "{'_id': 123}"); /* cursor is completed */ assert (!mongoc_cursor_next (cursor, &doc)); mongoc_cursor_destroy (cursor); request_destroy (request); future_destroy (future); /* readConcern: majority */ rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_MAJORITY); mongoc_collection_set_read_concern (collection, rc); cursor = mongoc_collection_aggregate ( collection, MONGOC_QUERY_NONE, tmp_bson ("[{'a': 1}]"), NULL, NULL); ASSERT (cursor); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{" " 'aggregate' : 'collection'," " 'pipeline' : [{" " 'a' : 1" " }]," " 'cursor' : { }," " 'readConcern': { 'level': 'majority'}" "}" ); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'db.collection'," " 'firstBatch': [{'_id': 123}]" "}}"); ASSERT (future_get_bool (future)); ASSERT_MATCH (doc, "{'_id': 123}"); /* cursor is completed */ assert (!mongoc_cursor_next (cursor, &doc)); mongoc_cursor_destroy (cursor); request_destroy (request); future_destroy (future); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); } void test_collection_install (TestSuite *suite) { test_aggregate_install (suite); TestSuite_Add (suite, "/Collection/insert_bulk", test_insert_bulk); TestSuite_Add (suite, "/Collection/insert_bulk_empty", test_insert_bulk_empty); TestSuite_Add (suite, "/Collection/bulk_insert/legacy/large", test_legacy_bulk_insert_large); TestSuite_Add (suite, "/Collection/bulk_insert/legacy/oversized_middle", test_legacy_bulk_insert_oversized_middle); TestSuite_Add (suite, "/Collection/bulk_insert/legacy/oversized_middle_continue", test_legacy_bulk_insert_oversized_continue_middle); TestSuite_Add (suite, "/Collection/bulk_insert/legacy/oversized_first", test_legacy_bulk_insert_oversized_first); TestSuite_Add (suite, "/Collection/bulk_insert/legacy/oversized_first_continue", test_legacy_bulk_insert_oversized_first_continue); TestSuite_Add (suite, "/Collection/bulk_insert/legacy/oversized_last", test_legacy_bulk_insert_oversized_last); TestSuite_Add (suite, "/Collection/bulk_insert/legacy/oversized_last_continue", test_legacy_bulk_insert_oversized_last_continue); TestSuite_Add (suite, "/Collection/copy", test_copy); TestSuite_Add (suite, "/Collection/insert", test_insert); TestSuite_Add (suite, "/Collection/insert/oversize", test_legacy_insert_oversize_mongos); TestSuite_Add (suite, "/Collection/insert/keys", test_insert_command_keys); TestSuite_Add (suite, "/Collection/save", test_save); TestSuite_Add (suite, "/Collection/index", test_index); TestSuite_Add (suite, "/Collection/index_compound", test_index_compound); TestSuite_Add (suite, "/Collection/index_geo", test_index_geo); TestSuite_Add (suite, "/Collection/index_storage", test_index_storage); TestSuite_Add (suite, "/Collection/regex", test_regex); TestSuite_Add (suite, "/Collection/update", test_update); TestSuite_Add (suite, "/Collection/remove", test_remove); TestSuite_Add (suite, "/Collection/count", test_count); TestSuite_Add (suite, "/Collection/count_with_opts", test_count_with_opts); TestSuite_Add (suite, "/Collection/count/read_concern", test_count_read_concern); TestSuite_AddFull (suite, "/Collection/count/read_concern_live", test_count_read_concern_live, NULL, NULL, mongod_supports_majority_read_concern); TestSuite_Add (suite, "/Collection/drop", test_drop); TestSuite_Add (suite, "/Collection/aggregate", test_aggregate); TestSuite_Add (suite, "/Collection/aggregate/large", test_aggregate_large); TestSuite_Add (suite, "/Collection/aggregate/read_concern", test_aggregate_read_concern); TestSuite_AddFull (suite, "/Collection/aggregate/bypass_document_validation", test_aggregate_bypass, NULL, NULL, test_framework_skip_if_max_version_version_less_than_4); TestSuite_Add (suite, "/Collection/validate", test_validate); TestSuite_Add (suite, "/Collection/rename", test_rename); TestSuite_Add (suite, "/Collection/stats", test_stats); TestSuite_Add (suite, "/Collection/find_read_concern", test_find_read_concern); TestSuite_Add (suite, "/Collection/find_and_modify", test_find_and_modify); TestSuite_Add (suite, "/Collection/find_and_modify/write_concern", test_find_and_modify_write_concern_wire_32); TestSuite_Add (suite, "/Collection/find_and_modify/write_concern_pre_32", test_find_and_modify_write_concern_wire_pre_32); TestSuite_Add (suite, "/Collection/large_return", test_large_return); TestSuite_Add (suite, "/Collection/many_return", test_many_return); TestSuite_Add (suite, "/Collection/limit", test_find_limit); TestSuite_Add (suite, "/Collection/batch_size", test_find_batch_size); TestSuite_AddFull (suite, "/Collection/command_fully_qualified", test_command_fq, NULL, NULL, test_framework_skip_if_mongos); TestSuite_Add (suite, "/Collection/get_index_info", test_get_index_info); } libmongoc-1.3.1/tests/test-mongoc-cursor.c000066400000000000000000000401721264720626300205610ustar00rootroot00000000000000#include #include #include "TestSuite.h" #include "test-libmongoc.h" #include "mock_server/mock-rs.h" #include "mock_server/future-functions.h" #include "mongoc-cursor-private.h" #include "mongoc-collection-private.h" #include "test-conveniences.h" static mongoc_collection_t * get_test_collection (mongoc_client_t *client, const char *prefix) { mongoc_collection_t *ret; char *str; str = gen_collection_name (prefix); ret = mongoc_client_get_collection (client, "test", str); bson_free (str); return ret; } static void test_get_host (void) { const mongoc_host_list_t *hosts; mongoc_host_list_t host; mongoc_client_t *client; mongoc_cursor_t *cursor; char *uri_str = test_framework_get_uri_str (); mongoc_uri_t *uri; const bson_t *doc; bson_error_t error; bool r; bson_t q = BSON_INITIALIZER; uri = mongoc_uri_new (uri_str); hosts = mongoc_uri_get_hosts(uri); client = test_framework_client_new (); cursor = _mongoc_cursor_new(client, "test.test", MONGOC_QUERY_NONE, 0, 1, 1, false, &q, NULL, NULL, NULL); r = mongoc_cursor_next(cursor, &doc); if (!r && mongoc_cursor_error(cursor, &error)) { MONGOC_ERROR("%s", error.message); abort(); } assert (doc == mongoc_cursor_current (cursor)); mongoc_cursor_get_host(cursor, &host); /* In a production deployment the driver can discover servers not in the seed * list, but for this test assume the cursor uses one of the seeds. */ while (hosts) { if (!strcmp (host.host_and_port, hosts->host_and_port)) { /* the cursor is using this server */ ASSERT_CMPSTR (host.host, hosts->host); ASSERT_CMPINT (host.port, ==, hosts->port); ASSERT_CMPINT (host.family, ==, hosts->family); break; } hosts = hosts->next; } if (!hosts) { MONGOC_ERROR ("cursor using host %s not in seeds: %s", host.host_and_port, uri_str); abort (); } bson_free (uri_str); mongoc_uri_destroy(uri); mongoc_cursor_destroy (cursor); mongoc_client_destroy (client); } static void test_clone (void) { mongoc_cursor_t *clone; mongoc_cursor_t *cursor; mongoc_client_t *client; const bson_t *doc; bson_error_t error; bool r; bson_t q = BSON_INITIALIZER; client = test_framework_client_new (); { /* * Ensure test.test has a document. */ mongoc_collection_t *col; col = mongoc_client_get_collection (client, "test", "test"); r = mongoc_collection_insert (col, MONGOC_INSERT_NONE, &q, NULL, &error); ASSERT (r); mongoc_collection_destroy (col); } cursor = _mongoc_cursor_new(client, "test.test", MONGOC_QUERY_NONE, 0, 1, 1, false, &q, NULL, NULL, NULL); ASSERT(cursor); r = mongoc_cursor_next(cursor, &doc); if (!r || mongoc_cursor_error(cursor, &error)) { MONGOC_ERROR("%s", error.message); abort(); } ASSERT (doc); clone = mongoc_cursor_clone(cursor); ASSERT(cursor); r = mongoc_cursor_next(clone, &doc); if (!r || mongoc_cursor_error(clone, &error)) { MONGOC_ERROR("%s", error.message); abort(); } ASSERT (doc); mongoc_cursor_destroy(cursor); mongoc_cursor_destroy(clone); mongoc_client_destroy(client); } static void test_invalid_query (void) { mongoc_client_t *client; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc = NULL; bson_t *q; bool r; client = test_framework_client_new (); assert (client); q = BCON_NEW ("foo", BCON_INT32 (1), "$orderby", "{", "}"); cursor = _mongoc_cursor_new (client, "test.test", MONGOC_QUERY_NONE, 0, 1, 1, false, q, NULL, NULL, NULL); assert (!mongoc_cursor_is_alive (cursor)); r = mongoc_cursor_next (cursor, &doc); assert (!r); mongoc_cursor_error (cursor, &error); assert (strstr (error.message, "$query")); assert (error.domain == MONGOC_ERROR_CURSOR); assert (error.code == MONGOC_ERROR_CURSOR_INVALID_CURSOR); assert (doc == NULL); bson_destroy (q); mongoc_cursor_destroy (cursor); mongoc_client_destroy (client); } /* test killing a cursor with mongo_cursor_destroy and a real server */ static void test_kill_cursor_live (void) { mongoc_client_t *client; mongoc_collection_t *collection; bson_t *b; mongoc_bulk_operation_t *bulk; int i; bson_error_t error; uint32_t hint; bool r; mongoc_cursor_t *cursor; const bson_t *doc; int64_t cursor_id; client = test_framework_client_new (); collection = get_test_collection (client, "test"); b = tmp_bson ("{}"); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); for (i = 0; i < 200; i++) { mongoc_bulk_operation_insert (bulk, b); } hint = mongoc_bulk_operation_execute (bulk, NULL, &error); ASSERT_OR_PRINT (hint > 0, error); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, /* batch size 2 */ b, NULL, NULL); r = mongoc_cursor_next (cursor, &doc); ASSERT (r); cursor_id = mongoc_cursor_get_id (cursor); ASSERT (cursor_id); /* sends OP_KILLCURSORS or killCursors command to server */ mongoc_cursor_destroy (cursor); cursor = _mongoc_cursor_new (client, collection->ns, MONGOC_QUERY_NONE, 0, 0, 0, false /* is_command */, b, NULL, NULL, NULL); cursor->rpc.reply.cursor_id = cursor_id; cursor->sent = true; cursor->end_of_event = true; /* meaning, "finished reading first batch" */ r = mongoc_cursor_next (cursor, &doc); ASSERT (!r); ASSERT (mongoc_cursor_error (cursor, &error)); ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_CURSOR, 16, "cursor is invalid"); } /* test OP_KILLCURSORS or the killCursors command with mock servers */ static void _test_kill_cursors (bool pooled, bool use_killcursors_cmd) { mock_rs_t *rs; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; mongoc_collection_t *collection; bson_t *q = BCON_NEW ("a", BCON_INT32 (1)); mongoc_read_prefs_t *prefs; mongoc_cursor_t *cursor; const bson_t *doc = NULL; future_t *future; request_t *request; bson_error_t error; request_t *kill_cursors; const char *ns_out; int64_t cursor_id_out; rs = mock_rs_with_autoismaster ( use_killcursors_cmd ? 4 : 3, /* wire version */ true, /* has primary */ 5, /* number of secondaries */ 0); /* number of arbiters */ mock_rs_run (rs); if (pooled) { pool = mongoc_client_pool_new (mock_rs_get_uri (rs)); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new_from_uri (mock_rs_get_uri (rs)); } collection = mongoc_client_get_collection (client, "db", "collection"); prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, q, NULL, prefs); future = future_cursor_next (cursor, &doc); request = mock_rs_receives_request (rs); /* reply as appropriate to OP_QUERY or find command */ mock_rs_replies_to_find (request, MONGOC_QUERY_SLAVE_OK, 123, 1, "db.collection", "{'b': 1}", use_killcursors_cmd); if (!future_get_bool (future)) { mongoc_cursor_error (cursor, &error); fprintf (stderr, "%s\n", error.message); abort (); }; ASSERT_MATCH (doc, "{'b': 1}"); ASSERT_CMPINT (123, ==, (int) mongoc_cursor_get_id (cursor)); future_destroy (future); future = future_cursor_destroy (cursor); if (use_killcursors_cmd) { kill_cursors = mock_rs_receives_command ( rs, "db", MONGOC_QUERY_SLAVE_OK, NULL); /* mock server framework can't test "cursors" array, CDRIVER-994 */ ASSERT (BCON_EXTRACT ((bson_t *) request_get_doc (kill_cursors, 0), "killCursors", BCONE_UTF8 (ns_out), "cursors", "[", BCONE_INT64 (cursor_id_out), "]")); ASSERT_CMPSTR ("collection", ns_out); ASSERT_CMPINT64 ((int64_t) 123, ==, cursor_id_out); mock_rs_replies_simple (request, "{'ok': 1}"); } else { kill_cursors = mock_rs_receives_kill_cursors (rs, 123); } /* OP_KILLCURSORS was sent to the right secondary */ ASSERT_CMPINT (request_get_server_port (kill_cursors), ==, request_get_server_port (request)); assert (future_wait (future)); request_destroy (kill_cursors); request_destroy (request); future_destroy (future); mongoc_read_prefs_destroy (prefs); mongoc_collection_destroy (collection); bson_destroy (q); if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } mock_rs_destroy (rs); } static void test_kill_cursors_single (void) { _test_kill_cursors (false, false); } static void test_kill_cursors_pooled (void) { _test_kill_cursors (true, false); } static void test_kill_cursors_single_cmd (void) { _test_kill_cursors (false, true); } static void test_kill_cursors_pooled_cmd (void) { _test_kill_cursors (true, true); } static void _test_getmore_fail (bool has_primary, bool pooled) { mock_rs_t *rs; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; mongoc_collection_t *collection; bson_t *q = BCON_NEW ("a", BCON_INT32 (1)); mongoc_read_prefs_t *prefs; mongoc_cursor_t *cursor; const bson_t *doc = NULL; future_t *future; request_t *request; /* wire version 0, five secondaries, no arbiters */ rs = mock_rs_with_autoismaster (0, has_primary, 5, 0); mock_rs_run (rs); if (pooled) { pool = mongoc_client_pool_new (mock_rs_get_uri (rs)); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new_from_uri (mock_rs_get_uri (rs)); } collection = mongoc_client_get_collection (client, "test", "test"); prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, q, NULL, prefs); future = future_cursor_next (cursor, &doc); request = mock_rs_receives_query (rs, "test.test", MONGOC_QUERY_SLAVE_OK, 0, 0, "{'a': 1}", NULL); mock_rs_replies (request, 0, 123, 0, 1, "{'b': 1}"); assert (future_get_bool (future)); ASSERT_MATCH (doc, "{'b': 1}"); ASSERT_CMPINT (123, ==, (int) mongoc_cursor_get_id (cursor)); future_destroy (future); future = future_cursor_next (cursor, &doc); request = mock_rs_receives_getmore (rs, "test.test", 0, 123); suppress_one_message (); mock_rs_hangs_up (request); assert (! future_get_bool (future)); request_destroy (request); future_destroy (future); future = future_cursor_destroy (cursor); /* driver does not reconnect just to send killcursors */ mock_rs_set_request_timeout_msec (rs, 100); assert (! mock_rs_receives_kill_cursors (rs, 123)); future_wait (future); future_destroy (future); mongoc_read_prefs_destroy (prefs); mongoc_collection_destroy (collection); bson_destroy (q); if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } mock_rs_destroy (rs); } static void test_getmore_fail_with_primary_single (void) { _test_getmore_fail (true, false); } static void test_getmore_fail_with_primary_pooled (void) { _test_getmore_fail (true, true); } static void test_getmore_fail_no_primary_pooled (void) { _test_getmore_fail (false, true); } static void test_getmore_fail_no_primary_single (void) { _test_getmore_fail (false, false); } /* We already test that mongoc_cursor_destroy sends OP_KILLCURSORS in * test_kill_cursors_single / pooled. Here, test explicit * mongoc_client_kill_cursor. */ static void _test_client_kill_cursor (bool has_primary, bool wire_version_4) { mock_rs_t *rs; mongoc_client_t *client; mongoc_read_prefs_t *read_prefs; bson_error_t error; future_t *future; request_t *request; rs = mock_rs_with_autoismaster (wire_version_4 ? 4 : 3, has_primary, /* maybe a primary*/ 1, /* definitely a secondary */ 0); /* no arbiter */ mock_rs_run (rs); client = mongoc_client_new_from_uri (mock_rs_get_uri (rs)); read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); /* make client open a connection - it won't open one to kill a cursor */ future = future_client_command_simple (client, "admin", tmp_bson ("{'foo': 1}"), read_prefs, NULL, &error); request = mock_rs_receives_command (rs, "admin", MONGOC_QUERY_SLAVE_OK, NULL); mock_rs_replies_simple (request, "{'ok': 1}"); ASSERT_OR_PRINT (future_get_bool (future), error); request_destroy (request); future_destroy (future); future = future_client_kill_cursor (client, 123); mock_rs_set_request_timeout_msec (rs, 100); /* we don't pass namespace so client always sends legacy OP_KILLCURSORS */ request = mock_rs_receives_kill_cursors (rs, 123); if (has_primary) { assert (request); /* weird but true. see mongoc_client_kill_cursor's documentation */ assert (mock_rs_request_is_to_primary (rs, request)); request_destroy (request); /* server has no reply to OP_KILLCURSORS */ } else { /* TODO: catch and check warning */ assert (!request); } future_wait (future); /* no return value */ future_destroy (future); mongoc_read_prefs_destroy (read_prefs); mongoc_client_destroy (client); mock_rs_destroy (rs); } static void test_client_kill_cursor_with_primary (void) { _test_client_kill_cursor (true, false); } static void test_client_kill_cursor_without_primary (void) { _test_client_kill_cursor (false, false); } static void test_client_kill_cursor_with_primary_wire_version_4 (void) { _test_client_kill_cursor (true, true); } static void test_client_kill_cursor_without_primary_wire_version_4 (void) { _test_client_kill_cursor (false, true); } void test_cursor_install (TestSuite *suite) { TestSuite_Add (suite, "/Cursor/get_host", test_get_host); TestSuite_Add (suite, "/Cursor/clone", test_clone); TestSuite_Add (suite, "/Cursor/invalid_query", test_invalid_query); TestSuite_Add (suite, "/Cursor/kill/live", test_kill_cursor_live); TestSuite_Add (suite, "/Cursor/kill/single", test_kill_cursors_single); TestSuite_Add (suite, "/Cursor/kill/pooled", test_kill_cursors_pooled); TestSuite_Add (suite, "/Cursor/kill/single/cmd", test_kill_cursors_single_cmd); TestSuite_Add (suite, "/Cursor/kill/pooled/cmd", test_kill_cursors_pooled_cmd); TestSuite_Add (suite, "/Cursor/getmore_fail/with_primary/pooled", test_getmore_fail_with_primary_pooled); TestSuite_Add (suite, "/Cursor/getmore_fail/with_primary/single", test_getmore_fail_with_primary_single); TestSuite_Add (suite, "/Cursor/getmore_fail/no_primary/pooled", test_getmore_fail_no_primary_pooled); TestSuite_Add (suite, "/Cursor/getmore_fail/no_primary/single", test_getmore_fail_no_primary_single); TestSuite_Add (suite, "/Cursor/client_kill_cursor/with_primary", test_client_kill_cursor_with_primary); TestSuite_Add (suite, "/Cursor/client_kill_cursor/without_primary", test_client_kill_cursor_without_primary); TestSuite_Add (suite, "/Cursor/client_kill_cursor/with_primary/wv4", test_client_kill_cursor_with_primary_wire_version_4); TestSuite_Add (suite, "/Cursor/client_kill_cursor/without_primary/wv4", test_client_kill_cursor_without_primary_wire_version_4); } libmongoc-1.3.1/tests/test-mongoc-database.c000066400000000000000000000333471264720626300210160ustar00rootroot00000000000000#include #include "TestSuite.h" #include "test-libmongoc.h" #include "mongoc-tests.h" #include "mongoc-client-private.h" #include "mongoc-database-private.h" #include "mock_server/future-functions.h" #include "mock_server/mock-server.h" static void test_copy (void) { mongoc_database_t *database; mongoc_database_t *copy; mongoc_client_t *client; client = test_framework_client_new (); ASSERT (client); database = mongoc_client_get_database (client, "test"); ASSERT (database); copy = mongoc_database_copy(database); ASSERT (copy); ASSERT (copy->client == database->client); ASSERT (strcmp(copy->name, database->name) == 0); mongoc_database_destroy(copy); mongoc_database_destroy(database); mongoc_client_destroy(client); } static void test_has_collection (void) { mongoc_collection_t *collection; mongoc_database_t *database; mongoc_client_t *client; bson_error_t error; char *name; bool r; bson_oid_t oid; bson_t b; client = test_framework_client_new (); assert (client); name = gen_collection_name ("has_collection"); collection = mongoc_client_get_collection (client, "test", name); assert (collection); database = mongoc_client_get_database (client, "test"); assert (database); bson_init (&b); bson_oid_init (&oid, NULL); bson_append_oid (&b, "_id", 3, &oid); bson_append_utf8 (&b, "hello", 5, "world", 5); ASSERT_OR_PRINT (mongoc_collection_insert (collection, MONGOC_INSERT_NONE, &b, NULL, &error), error); bson_destroy (&b); r = mongoc_database_has_collection (database, name, &error); assert (!error.domain); assert (r); bson_free (name); mongoc_database_destroy (database); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_command (void) { mongoc_database_t *database; mongoc_client_t *client; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; bool r; bson_t cmd = BSON_INITIALIZER; bson_t reply; client = test_framework_client_new (); assert (client); database = mongoc_client_get_database (client, "admin"); /* * Test a known working command, "ping". */ bson_append_int32 (&cmd, "ping", 4, 1); cursor = mongoc_database_command (database, MONGOC_QUERY_NONE, 0, 1, 0, &cmd, NULL, NULL); assert (cursor); r = mongoc_cursor_next (cursor, &doc); assert (r); assert (doc); r = mongoc_cursor_next (cursor, &doc); assert (!r); assert (!doc); mongoc_cursor_destroy (cursor); /* * Test a non-existing command to ensure we get the failure. */ bson_reinit (&cmd); bson_append_int32 (&cmd, "a_non_existing_command", -1, 1); r = mongoc_database_command_simple (database, &cmd, NULL, &reply, &error); assert (!r); assert (error.domain == MONGOC_ERROR_QUERY); assert (error.code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND); assert (strstr (error.message, "a_non_existing_command")); mongoc_database_destroy (database); mongoc_client_destroy (client); bson_destroy (&cmd); } static void test_drop (void) { mongoc_database_t *database; mongoc_client_t *client; bson_error_t error = { 0 }; char *dbname; client = test_framework_client_new (); assert (client); dbname = gen_collection_name ("db_drop_test"); database = mongoc_client_get_database (client, dbname); bson_free (dbname); ASSERT_OR_PRINT (mongoc_database_drop (database, &error), error); assert (!error.domain); assert (!error.code); mongoc_database_destroy (database); mongoc_client_destroy (client); } static void test_create_collection (void) { mongoc_database_t *database; mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error = { 0 }; bson_t options; bson_t storage_opts; bson_t wt_opts; char *dbname; char *name; client = test_framework_client_new (); assert (client); dbname = gen_collection_name ("dbtest"); database = mongoc_client_get_database (client, dbname); assert (database); bson_free (dbname); bson_init (&options); BSON_APPEND_INT32 (&options, "size", 1234); BSON_APPEND_INT32 (&options, "max", 4567); BSON_APPEND_BOOL (&options, "capped", true); BSON_APPEND_BOOL (&options, "autoIndexId", true); BSON_APPEND_DOCUMENT_BEGIN(&options, "storage", &storage_opts); BSON_APPEND_DOCUMENT_BEGIN(&storage_opts, "wiredtiger", &wt_opts); BSON_APPEND_UTF8(&wt_opts, "configString", "block_compressor=zlib"); bson_append_document_end(&storage_opts, &wt_opts); bson_append_document_end(&options, &storage_opts); name = gen_collection_name ("create_collection"); ASSERT_OR_PRINT ( collection = mongoc_database_create_collection (database, name, &options, &error), error); bson_destroy (&options); bson_free (name); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); ASSERT_OR_PRINT (mongoc_database_drop (database, &error), error); mongoc_collection_destroy (collection); mongoc_database_destroy (database); mongoc_client_destroy (client); } static void test_get_collection_info (void) { mongoc_database_t *database; mongoc_collection_t *collection; mongoc_client_t *client; mongoc_cursor_t *cursor; bson_error_t error = { 0 }; bson_iter_t col_iter; bson_t capped_options = BSON_INITIALIZER; bson_t autoindexid_options = BSON_INITIALIZER; bson_t noopts_options = BSON_INITIALIZER; bson_t name_filter = BSON_INITIALIZER; const bson_t *doc; int num_infos = 0; const char *name; char *dbname; char *capped_name; char *autoindexid_name; char *noopts_name; client = test_framework_client_new (); assert (client); dbname = gen_collection_name ("dbtest"); database = mongoc_client_get_database (client, dbname); assert (database); bson_free (dbname); capped_name = gen_collection_name ("capped"); BSON_APPEND_BOOL (&capped_options, "capped", true); BSON_APPEND_INT32 (&capped_options, "size", 10000000); BSON_APPEND_INT32 (&capped_options, "max", 1024); autoindexid_name = gen_collection_name ("autoindexid"); BSON_APPEND_BOOL (&autoindexid_options, "autoIndexId", false); noopts_name = gen_collection_name ("noopts"); collection = mongoc_database_create_collection (database, capped_name, &capped_options, &error); ASSERT_OR_PRINT (collection, error); mongoc_collection_destroy (collection); collection = mongoc_database_create_collection (database, autoindexid_name, &autoindexid_options, &error); ASSERT_OR_PRINT (collection, error); mongoc_collection_destroy (collection); collection = mongoc_database_create_collection (database, noopts_name, &noopts_options, &error); ASSERT_OR_PRINT (collection, error); mongoc_collection_destroy (collection); /* first we filter on collection name. */ BSON_APPEND_UTF8 (&name_filter, "name", noopts_name); /* We only test with filters since get_collection_names will * test w/o filters for us. */ /* Filter on an exact match of name */ cursor = mongoc_database_find_collections (database, &name_filter, &error); assert (cursor); assert (!error.domain); assert (!error.code); while (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init (&col_iter, doc) && bson_iter_find (&col_iter, "name") && BSON_ITER_HOLDS_UTF8 (&col_iter) && (name = bson_iter_utf8 (&col_iter, NULL))) { ++num_infos; assert (0 == strcmp (name, noopts_name)); } else { assert (false); } } assert (1 == num_infos); mongoc_cursor_destroy (cursor); ASSERT_OR_PRINT (mongoc_database_drop (database, &error), error); assert (!error.domain); assert (!error.code); bson_free (capped_name); bson_free (noopts_name); bson_free (autoindexid_name); mongoc_database_destroy (database); mongoc_client_destroy (client); } static void test_get_collection_names (void) { mongoc_database_t *database; mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error = { 0 }; bson_t options; int namecount = 0; char **names; char **name; char *curname; char *dbname; char *name1; char *name2; char *name3; char *name4; char *name5; const char *system_prefix = "system."; client = test_framework_client_new (); assert (client); dbname = gen_collection_name ("dbtest"); database = mongoc_client_get_database (client, dbname); assert (database); bson_free (dbname); bson_init (&options); name1 = gen_collection_name ("name1"); name2 = gen_collection_name ("name2"); name3 = gen_collection_name ("name3"); name4 = gen_collection_name ("name4"); name5 = gen_collection_name ("name5"); collection = mongoc_database_create_collection (database, name1, &options, &error); assert (collection); mongoc_collection_destroy (collection); collection = mongoc_database_create_collection (database, name2, &options, &error); assert (collection); mongoc_collection_destroy (collection); collection = mongoc_database_create_collection (database, name3, &options, &error); assert (collection); mongoc_collection_destroy (collection); collection = mongoc_database_create_collection (database, name4, &options, &error); assert (collection); mongoc_collection_destroy (collection); collection = mongoc_database_create_collection (database, name5, &options, &error); assert (collection); mongoc_collection_destroy (collection); names = mongoc_database_get_collection_names (database, &error); assert (!error.domain); assert (!error.code); for (name = names; *name; ++name) { /* inefficient, but OK for a unit test. */ curname = *name; if (0 == strcmp (curname, name1) || 0 == strcmp (curname, name2) || 0 == strcmp (curname, name3) || 0 == strcmp (curname, name4) || 0 == strcmp (curname, name5)) { ++namecount; } else if (0 == strncmp (curname, system_prefix, strlen (system_prefix))) { /* Collections prefixed with 'system.' are system collections */ } else { assert (false); } bson_free (curname); } assert (namecount == 5); bson_free (name1); bson_free (name2); bson_free (name3); bson_free (name4); bson_free (name5); bson_free (names); ASSERT_OR_PRINT (mongoc_database_drop (database, &error), error); assert (!error.domain); assert (!error.code); mongoc_database_destroy (database); mongoc_client_destroy (client); } static void test_get_collection_names_error (void) { mongoc_database_t *database; mongoc_client_t *client; mock_server_t *server; bson_error_t error = { 0 }; bson_t b = BSON_INITIALIZER; future_t *future; request_t *request; char **names; server = mock_server_new (); mock_server_auto_ismaster (server, "{'ismaster': true," " 'maxWireVersion': 3}"); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); database = mongoc_client_get_database (client, "test"); suppress_one_message (); suppress_one_message (); future = future_database_get_collection_names (database, &error); request = mock_server_receives_command (server, "test", MONGOC_QUERY_SLAVE_OK, "{'listCollections': 1}"); mock_server_hangs_up (request); names = future_get_char_ptr_ptr (future); assert (!names); ASSERT_CMPINT (MONGOC_ERROR_STREAM, ==, error.domain); ASSERT_CMPINT (MONGOC_ERROR_STREAM_SOCKET, ==, error.code); request_destroy (request); future_destroy (future); mongoc_database_destroy (database); mongoc_client_destroy (client); mock_server_destroy (server); bson_destroy (&b); } static void test_get_default_database (void) { /* default database is "db_name" */ mongoc_client_t *client = mongoc_client_new ("mongodb://host/db_name"); mongoc_database_t *db = mongoc_client_get_default_database (client); assert (!strcmp ("db_name", mongoc_database_get_name (db))); mongoc_database_destroy (db); mongoc_client_destroy (client); /* no default database */ client = mongoc_client_new ("mongodb://host/"); db = mongoc_client_get_default_database (client); assert (!db); mongoc_client_destroy (client); } void test_database_install (TestSuite *suite) { TestSuite_Add (suite, "/Database/copy", test_copy); TestSuite_Add (suite, "/Database/has_collection", test_has_collection); TestSuite_Add (suite, "/Database/command", test_command); TestSuite_Add (suite, "/Database/drop", test_drop); TestSuite_Add (suite, "/Database/create_collection", test_create_collection); TestSuite_Add (suite, "/Database/get_collection_info", test_get_collection_info); TestSuite_Add (suite, "/Database/get_collection_names", test_get_collection_names); TestSuite_Add (suite, "/Database/get_collection_names_error", test_get_collection_names_error); TestSuite_Add (suite, "/Database/get_default_database", test_get_default_database); } libmongoc-1.3.1/tests/test-mongoc-exhaust.c000066400000000000000000000372771264720626300207410ustar00rootroot00000000000000#include #include #include "mongoc-client-private.h" #include "mongoc-cursor-private.h" #include "mongoc-uri-private.h" #include "mongoc-util-private.h" #include "TestSuite.h" #include "test-conveniences.h" #include "test-libmongoc.h" #include "mock_server/future.h" #include "mock_server/future-functions.h" #include "mock_server/mock-server.h" #include "mongoc-tests.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "exhaust-test" static mongoc_collection_t * get_test_collection (mongoc_client_t *client, const char *name) { mongoc_collection_t *ret; char *str; str = gen_collection_name (name); ret = mongoc_client_get_collection (client, "test", str); bson_free (str); return ret; } int skip_if_mongos (void) { return test_framework_is_mongos () ? 0 : 1; } static int64_t get_timestamp (mongoc_client_t *client, mongoc_cursor_t *cursor) { uint32_t hint; hint = mongoc_cursor_get_hint (cursor); if (client->topology->single_threaded) { mongoc_topology_scanner_node_t *scanner_node; scanner_node = mongoc_topology_scanner_get_node ( client->topology->scanner, hint); return scanner_node->timestamp; } else { mongoc_cluster_node_t *cluster_node; cluster_node = (mongoc_cluster_node_t *)mongoc_set_get( client->cluster.nodes, hint); return cluster_node->timestamp; } } static void test_exhaust_cursor (bool pooled) { mongoc_stream_t *stream; mongoc_write_concern_t *wr; mongoc_client_t *client; mongoc_client_pool_t *pool = NULL; mongoc_collection_t *collection; mongoc_cursor_t *cursor; mongoc_cursor_t *cursor2; const bson_t *doc; bson_t q; bson_t b[10]; bson_t *bptr[10]; int i; bool r; uint32_t hint; bson_error_t error; bson_oid_t oid; int64_t timestamp1; if (pooled) { pool = test_framework_client_pool_new (); client = mongoc_client_pool_pop (pool); } else { client = test_framework_client_new (); } assert (client); collection = get_test_collection (client, "test_exhaust_cursor"); assert (collection); mongoc_collection_drop(collection, &error); wr = mongoc_write_concern_new (); mongoc_write_concern_set_journal (wr, true); /* bulk insert some records to work on */ { bson_init(&q); for (i = 0; i < 10; i++) { bson_init(&b[i]); bson_oid_init(&oid, NULL); bson_append_oid(&b[i], "_id", -1, &oid); bson_append_int32(&b[i], "n", -1, i % 2); bptr[i] = &b[i]; } BEGIN_IGNORE_DEPRECATIONS; ASSERT_OR_PRINT (mongoc_collection_insert_bulk ( collection, MONGOC_INSERT_NONE, (const bson_t **)bptr, 10, wr, &error), error); END_IGNORE_DEPRECATIONS; } /* create a couple of cursors */ { cursor = mongoc_collection_find (collection, MONGOC_QUERY_EXHAUST, 0, 0, 0, &q, NULL, NULL); cursor2 = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &q, NULL, NULL); } /* Read from the exhaust cursor, ensure that we're in exhaust where we * should be and ensure that an early destroy properly causes a disconnect * */ { r = mongoc_cursor_next (cursor, &doc); if (!r) { mongoc_cursor_error (cursor, &error); fprintf (stderr, "cursor error: %s\n", error.message); } assert (r); assert (doc); assert (cursor->in_exhaust); assert (client->in_exhaust); /* destroy the cursor, make sure a disconnect happened */ timestamp1 = get_timestamp (client, cursor); mongoc_cursor_destroy (cursor); assert (! client->in_exhaust); } /* ensure even a 1 ms-resolution clock advances significantly */ _mongoc_usleep (10 * 1000); /* Grab a new exhaust cursor, then verify that reading from that cursor * (putting the client into exhaust), breaks a mid-stream read from a * regular cursor */ { cursor = mongoc_collection_find (collection, MONGOC_QUERY_EXHAUST, 0, 0, 0, &q, NULL, NULL); r = mongoc_cursor_next (cursor2, &doc); if (!r) { mongoc_cursor_error (cursor2, &error); fprintf (stderr, "cursor error: %s\n", error.message); } assert (r); assert (doc); assert (timestamp1 < get_timestamp (client, cursor2)); for (i = 0; i < 5; i++) { r = mongoc_cursor_next (cursor2, &doc); if (!r) { mongoc_cursor_error (cursor2, &error); fprintf (stderr, "cursor error: %s\n", error.message); } assert (r); assert (doc); } r = mongoc_cursor_next (cursor, &doc); assert (r); assert (doc); doc = NULL; r = mongoc_cursor_next (cursor2, &doc); assert (!r); assert (!doc); mongoc_cursor_error(cursor2, &error); assert (error.domain == MONGOC_ERROR_CLIENT); assert (error.code == MONGOC_ERROR_CLIENT_IN_EXHAUST); mongoc_cursor_destroy (cursor2); } /* make sure writes fail as well */ { BEGIN_IGNORE_DEPRECATIONS; r = mongoc_collection_insert_bulk (collection, MONGOC_INSERT_NONE, (const bson_t **)bptr, 10, wr, &error); END_IGNORE_DEPRECATIONS; assert (!r); assert (error.domain == MONGOC_ERROR_CLIENT); assert (error.code == MONGOC_ERROR_CLIENT_IN_EXHAUST); } /* we're still in exhaust. * * 1. check that we can create a new cursor, as long as we don't read from it * 2. fully exhaust the exhaust cursor * 3. make sure that we don't disconnect at destroy * 4. make sure we can read the cursor we made during the exhuast */ { cursor2 = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &q, NULL, NULL); stream = (mongoc_stream_t *)mongoc_set_get(client->cluster.nodes, cursor->hint); hint = cursor->hint; for (i = 1; i < 10; i++) { r = mongoc_cursor_next (cursor, &doc); assert (r); assert (doc); } r = mongoc_cursor_next (cursor, &doc); assert (!r); assert (!doc); mongoc_cursor_destroy (cursor); assert (stream == (mongoc_stream_t *)mongoc_set_get(client->cluster.nodes, hint)); r = mongoc_cursor_next (cursor2, &doc); assert (r); assert (doc); } bson_destroy(&q); for (i = 0; i < 10; i++) { bson_destroy(&b[i]); } ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_write_concern_destroy (wr); mongoc_cursor_destroy (cursor2); mongoc_collection_destroy(collection); if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } } static void test_exhaust_cursor_single (void *context) { test_exhaust_cursor (false); } static void test_exhaust_cursor_pool (void *context) { test_exhaust_cursor (true); } static void test_exhaust_cursor_multi_batch (void *context) { mongoc_client_t *client; bson_error_t error; mongoc_collection_t *collection; bson_t doc = BSON_INITIALIZER; mongoc_bulk_operation_t *bulk; int i; uint32_t hint; mongoc_cursor_t *cursor; const bson_t *cursor_doc; client = test_framework_client_new (); collection = get_test_collection (client, "test_exhaust_cursor_multi_batch"); ASSERT_OR_PRINT (collection, error); BSON_APPEND_UTF8 (&doc, "key", "value"); bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); /* enough to require more than initial batch */ for (i = 0; i < 1000; i++) { mongoc_bulk_operation_insert (bulk, &doc); } hint = mongoc_bulk_operation_execute (bulk, NULL, &error); ASSERT_OR_PRINT (hint, error); cursor = mongoc_collection_find ( collection, MONGOC_QUERY_EXHAUST, 0, 0, 0, tmp_bson ("{}"), NULL, NULL); i = 0; while (mongoc_cursor_next (cursor, &cursor_doc)) { i++; } ASSERT_OR_PRINT (!mongoc_cursor_error (cursor, &error), error); ASSERT_CMPINT (i, ==, 1000); mongoc_cursor_destroy (cursor); mongoc_bulk_operation_destroy (bulk); mongoc_collection_destroy (collection); bson_destroy (&doc); mongoc_client_destroy (client); } static void test_cursor_set_max_await_time_ms (void) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; client = test_framework_client_new (); collection = get_test_collection (client, "test_cursor_set_max_await_time_ms"); cursor = mongoc_collection_find ( collection, MONGOC_QUERY_TAILABLE_CURSOR|MONGOC_QUERY_AWAIT_DATA, 0, 0, 0, tmp_bson ("{}"), NULL, NULL); ASSERT_CMPINT (0, ==, mongoc_cursor_get_max_await_time_ms (cursor)); mongoc_cursor_set_max_await_time_ms (cursor, 123); ASSERT_CMPINT (123, ==, mongoc_cursor_get_max_await_time_ms (cursor)); _mongoc_cursor_next (cursor, NULL); /* once started, cursor ignores set_max_await_time_ms () */ mongoc_cursor_set_max_await_time_ms (cursor, 42); ASSERT_CMPINT (123, ==, mongoc_cursor_get_max_await_time_ms (cursor)); } typedef enum { FIRST_BATCH, SECOND_BATCH, } exhaust_error_when_t; typedef enum { NETWORK_ERROR, SERVER_ERROR, } exhaust_error_type_t; static void _request_error (request_t *request, exhaust_error_type_t error_type) { if (error_type == NETWORK_ERROR) { mock_server_resets (request); } else { mock_server_replies (request, MONGOC_REPLY_QUERY_FAILURE, 123, 0, 0, "{'$err': 'uh oh', 'code': 4321}"); } } static void _check_error (mongoc_client_t *client, mongoc_cursor_t *cursor, bool pooled, exhaust_error_type_t error_type) { uint32_t hint; bson_error_t error; hint = mongoc_cursor_get_hint (cursor); ASSERT (hint); ASSERT (mongoc_cursor_error (cursor, &error)); if (error_type == NETWORK_ERROR) { ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to read"); /* socket was discarded */ ASSERT (!mongoc_cluster_stream_for_server (&client->cluster, hint, false /* don't reconnect */, &error)); ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, pooled ? "Could not find node" : "Could not find stream"); } else { /* query failure */ ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_QUERY, 4321 /* error from mock server */, "uh oh" /* message from mock server */); } } static void _mock_test_exhaust (bool pooled, exhaust_error_when_t error_when, exhaust_error_type_t error_type) { mock_server_t *server; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; const bson_t *doc; future_t *future; request_t *request; server = mock_server_with_autoismaster (0); mock_server_run (server); if (pooled) { pool = mongoc_client_pool_new (mock_server_get_uri (server)); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new_from_uri (mock_server_get_uri (server)); } collection = mongoc_client_get_collection (client, "db", "test"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_EXHAUST, 0, 0, 0, tmp_bson ("{}"), NULL, NULL); future = future_cursor_next (cursor, &doc); request = mock_server_receives_query ( server, "db.test", MONGOC_QUERY_SLAVE_OK | MONGOC_QUERY_EXHAUST, 0, 0, "{}", NULL); if (error_when == SECOND_BATCH) { /* initial query succeeds, gets a doc and cursor id of 123 */ mock_server_replies (request, MONGOC_REPLY_NONE, 123, 1, 1, "{'a': 1}"); ASSERT (future_get_bool (future)); ASSERT (match_bson (doc, tmp_bson ("{'a': 1}"), false)); ASSERT_CMPINT64 ((int64_t) 123, ==, mongoc_cursor_get_id (cursor)); future_destroy (future); /* error after initial batch */ future = future_cursor_next (cursor, &doc); } suppress_one_message (); _request_error (request, error_type); ASSERT (!future_get_bool (future)); _check_error (client, cursor, pooled, error_type); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } mock_server_destroy (server); } static void test_exhaust_network_err_1st_batch_single (void) { _mock_test_exhaust (false, FIRST_BATCH, NETWORK_ERROR); } static void test_exhaust_network_err_1st_batch_pooled (void) { _mock_test_exhaust (true, FIRST_BATCH, NETWORK_ERROR); } static void test_exhaust_server_err_1st_batch_single (void) { _mock_test_exhaust (false, FIRST_BATCH, SERVER_ERROR); } static void test_exhaust_server_err_1st_batch_pooled (void) { _mock_test_exhaust (true, FIRST_BATCH, SERVER_ERROR); } static void test_exhaust_network_err_2nd_batch_single (void) { _mock_test_exhaust (false, SECOND_BATCH, NETWORK_ERROR); } static void test_exhaust_network_err_2nd_batch_pooled (void) { _mock_test_exhaust (true, SECOND_BATCH, NETWORK_ERROR); } static void test_exhaust_server_err_2nd_batch_single (void) { _mock_test_exhaust (false, SECOND_BATCH, SERVER_ERROR); } static void test_exhaust_server_err_2nd_batch_pooled (void) { _mock_test_exhaust (true, SECOND_BATCH, SERVER_ERROR); } void test_exhaust_install (TestSuite *suite) { TestSuite_AddFull (suite, "/Client/exhaust_cursor/single", test_exhaust_cursor_single, NULL, NULL, skip_if_mongos); TestSuite_AddFull (suite, "/Client/exhaust_cursor/pool", test_exhaust_cursor_pool, NULL, NULL, skip_if_mongos); TestSuite_AddFull (suite, "/Client/exhaust_cursor/batches", test_exhaust_cursor_multi_batch, NULL, NULL, skip_if_mongos); TestSuite_Add (suite, "/Client/set_max_await_time_ms", test_cursor_set_max_await_time_ms); TestSuite_Add (suite, "/Client/exhaust_cursor/err/network/1st_batch/single", test_exhaust_network_err_1st_batch_single); TestSuite_Add (suite, "/Client/exhaust_cursor/err/network/1st_batch/pooled", test_exhaust_network_err_1st_batch_pooled); TestSuite_Add (suite, "/Client/exhaust_cursor/err/server/1st_batch/single", test_exhaust_server_err_1st_batch_single); TestSuite_Add (suite, "/Client/exhaust_cursor/err/server/1st_batch/pooled", test_exhaust_server_err_1st_batch_pooled); TestSuite_Add (suite, "/Client/exhaust_cursor/err/network/2nd_batch/single", test_exhaust_network_err_2nd_batch_single); TestSuite_Add (suite, "/Client/exhaust_cursor/err/network/2nd_batch/pooled", test_exhaust_network_err_2nd_batch_pooled); TestSuite_Add (suite, "/Client/exhaust_cursor/err/server/2nd_batch/single", test_exhaust_server_err_2nd_batch_single); TestSuite_Add (suite, "/Client/exhaust_cursor/err/server/2nd_batch/pooled", test_exhaust_server_err_2nd_batch_pooled); } libmongoc-1.3.1/tests/test-mongoc-find-and-modify.c000066400000000000000000000276601264720626300222200ustar00rootroot00000000000000#include #include #include #include #include #include "TestSuite.h" #include "test-libmongoc.h" #include "test-conveniences.h" #include "mongoc-tests.h" #include "mock_server/future-functions.h" #include "mock_server/mock-server.h" static void auto_ismaster (mock_server_t *server, int32_t max_wire_version, int32_t max_message_size, int32_t max_bson_size, int32_t max_batch_size) { char *response = bson_strdup_printf ( "{'ismaster': true, " " 'maxWireVersion': %d," " 'maxBsonObjectSize': %d," " 'maxMessageSizeBytes': %d," " 'maxWriteBatchSize': %d }", max_wire_version, max_bson_size, max_message_size, max_batch_size); mock_server_auto_ismaster (server, response); bson_free (response); } int should_run_fam_wc (void) { if (test_framework_is_replset()) { return test_framework_max_wire_version_at_least (WIRE_VERSION_FAM_WRITE_CONCERN); } return 0; } static mongoc_collection_t * get_test_collection (mongoc_client_t *client, const char *prefix) { mongoc_collection_t *ret; char *str; str = gen_collection_name (prefix); ret = mongoc_client_get_collection (client, "test", str); bson_free (str); return ret; } static void test_find_and_modify_bypass (bool bypass) { mongoc_collection_t *collection; mongoc_client_t *client; mock_server_t *server; request_t *request; future_t *future; bson_error_t error; bson_t *update; bson_t doc = BSON_INITIALIZER; bson_t reply; mongoc_find_and_modify_opts_t *opts; server = mock_server_new (); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test_find_and_modify"); auto_ismaster (server, WIRE_VERSION_FAM_WRITE_CONCERN, /* max_wire_version */ 48000000, /* max_message_size */ 16777216, /* max_bson_size */ 1000); /* max_write_batch_size */ BSON_APPEND_INT32 (&doc, "superduper", 77889); update = BCON_NEW ("$set", "{", "superduper", BCON_INT32 (1234), "}"); opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_bypass_document_validation (opts, bypass); mongoc_find_and_modify_opts_set_update (opts, update); mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_RETURN_NEW); future = future_collection_find_and_modify_with_opts (collection, &doc, opts, &reply, &error); if (bypass) { request = mock_server_receives_command (server, "test", MONGOC_QUERY_NONE, "{ 'findAndModify' : 'test_find_and_modify', " "'query' : { 'superduper' : 77889 }," "'update' : { '$set' : { 'superduper' : 1234 } }," "'new' : true," "'bypassDocumentValidation' : true }"); } else { request = mock_server_receives_command (server, "test", MONGOC_QUERY_NONE, "{ 'findAndModify' : 'test_find_and_modify', " "'query' : { 'superduper' : 77889 }," "'update' : { '$set' : { 'superduper' : 1234 } }," "'new' : true," "'bypassDocumentValidation' : false }"); } mock_server_replies_simple (request, "{ 'value' : null, 'ok' : 1 }"); ASSERT_OR_PRINT (future_get_bool (future), error); future_destroy (future); mongoc_find_and_modify_opts_destroy (opts); bson_destroy (&reply); bson_destroy (update); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); bson_destroy (&doc); } static void test_find_and_modify_bypass_true (void) { test_find_and_modify_bypass (true); } static void test_find_and_modify_bypass_false (void) { test_find_and_modify_bypass (false); } static void test_find_and_modify_write_concern (int wire_version) { mongoc_collection_t *collection; mongoc_client_t *client; mock_server_t *server; request_t *request; future_t *future; bson_error_t error; bson_t *update; bson_t doc = BSON_INITIALIZER; bson_t reply; mongoc_find_and_modify_opts_t *opts; mongoc_write_concern_t *write_concern; server = mock_server_new (); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test_find_and_modify"); auto_ismaster (server, wire_version, /* max_wire_version */ 48000000, /* max_message_size */ 16777216, /* max_bson_size */ 1000); /* max_write_batch_size */ BSON_APPEND_INT32 (&doc, "superduper", 77889); update = BCON_NEW ("$set", "{", "superduper", BCON_INT32 (1234), "}"); write_concern = mongoc_write_concern_new (); mongoc_write_concern_set_w (write_concern, 42); opts = mongoc_find_and_modify_opts_new (); mongoc_collection_set_write_concern (collection, write_concern); mongoc_find_and_modify_opts_set_update (opts, update); mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_RETURN_NEW); future = future_collection_find_and_modify_with_opts (collection, &doc, opts, &reply, &error); if (wire_version >= 4) { request = mock_server_receives_command (server, "test", MONGOC_QUERY_NONE, "{ 'findAndModify' : 'test_find_and_modify', " "'query' : { 'superduper' : 77889 }," "'update' : { '$set' : { 'superduper' : 1234 } }," "'new' : true," "'writeConcern' : { 'w' : 42 } }"); } else { request = mock_server_receives_command (server, "test", MONGOC_QUERY_NONE, "{ 'findAndModify' : 'test_find_and_modify', " "'query' : { 'superduper' : 77889 }," "'update' : { '$set' : { 'superduper' : 1234 } }," "'new' : true }"); } mock_server_replies_simple (request, "{ 'value' : null, 'ok' : 1 }"); ASSERT_OR_PRINT (future_get_bool (future), error); future_destroy (future); mongoc_find_and_modify_opts_destroy (opts); bson_destroy (&reply); bson_destroy (update); mongoc_write_concern_destroy (write_concern); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&doc); mock_server_destroy (server); } static void test_find_and_modify_write_concern_wire_32_failure (void *context) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; mongoc_find_and_modify_opts_t *opts; bson_t reply; bson_t query = BSON_INITIALIZER; bson_t *update; bool success; mongoc_write_concern_t *wc; client = test_framework_client_new (); collection = get_test_collection (client, "writeFailure"); wc = mongoc_write_concern_new (); mongoc_write_concern_set_w (wc, 42); mongoc_collection_set_write_concern (collection, wc); /* Find Zlatan Ibrahimovic, the striker */ BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); BSON_APPEND_UTF8 (&query, "profession", "Football player"); BSON_APPEND_INT32 (&query, "age", 34); BSON_APPEND_INT32 (&query, "goals", (16+35+23+57+16+14+28+84)+(1+6+62)); /* Add his football position */ update = BCON_NEW ("$set", "{", "position", BCON_UTF8 ("striker"), "}"); opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_update (opts, update); /* Create the document if it didn't exist, and return the updated document */ mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_UPSERT|MONGOC_FIND_AND_MODIFY_RETURN_NEW); success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); ASSERT (success); ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_WRITE_CONCERN, 100, "Write Concern error:"); bson_destroy (&reply); bson_destroy (update); bson_destroy (&query); mongoc_find_and_modify_opts_destroy (opts); mongoc_collection_drop (collection, NULL); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_find_and_modify_write_concern_wire_32 (void) { test_find_and_modify_write_concern (4); } static void test_find_and_modify_write_concern_wire_pre_32 (void) { test_find_and_modify_write_concern (2); } static void test_find_and_modify (void) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error; bson_iter_t iter; bson_iter_t citer; bson_t *update; bson_t doc = BSON_INITIALIZER; bson_t reply; mongoc_find_and_modify_opts_t *opts; client = test_framework_client_new (); ASSERT (client); collection = get_test_collection (client, "test_find_and_modify"); ASSERT (collection); BSON_APPEND_INT32 (&doc, "superduper", 77889); ASSERT_OR_PRINT (mongoc_collection_insert ( collection, MONGOC_INSERT_NONE, &doc, NULL, &error), error); update = BCON_NEW ("$set", "{", "superduper", BCON_INT32 (1234), "}"); opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_update (opts, update); mongoc_find_and_modify_opts_set_fields (opts, tmp_bson ("{'superduper': 1}")); mongoc_find_and_modify_opts_set_sort (opts, tmp_bson ("{'superduper': 1}")); mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_RETURN_NEW); ASSERT_OR_PRINT (mongoc_collection_find_and_modify_with_opts (collection, &doc, opts, &reply, &error), error); assert (bson_iter_init_find (&iter, &reply, "value")); assert (BSON_ITER_HOLDS_DOCUMENT (&iter)); assert (bson_iter_recurse (&iter, &citer)); assert (bson_iter_find (&citer, "superduper")); assert (BSON_ITER_HOLDS_INT32 (&citer)); assert (bson_iter_int32 (&citer) == 1234); assert (bson_iter_init_find (&iter, &reply, "lastErrorObject")); assert (BSON_ITER_HOLDS_DOCUMENT (&iter)); assert (bson_iter_recurse (&iter, &citer)); assert (bson_iter_find (&citer, "updatedExisting")); assert (BSON_ITER_HOLDS_BOOL (&citer)); assert (bson_iter_bool (&citer)); bson_destroy (&reply); bson_destroy (update); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_find_and_modify_opts_destroy (opts); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&doc); } void test_find_and_modify_install (TestSuite *suite) { TestSuite_Add (suite, "/find_and_modify/find_and_modify", test_find_and_modify); TestSuite_Add (suite, "/find_and_modify/find_and_modify/bypass/true", test_find_and_modify_bypass_true); TestSuite_Add (suite, "/find_and_modify/find_and_modify/bypass/false", test_find_and_modify_bypass_false); TestSuite_Add (suite, "/find_and_modify/find_and_modify/write_concern", test_find_and_modify_write_concern_wire_32); TestSuite_Add (suite, "/find_and_modify/find_and_modify/write_concern_pre_32", test_find_and_modify_write_concern_wire_pre_32); TestSuite_AddFull (suite, "/find_and_modify/find_and_modify/write_concern_failure", test_find_and_modify_write_concern_wire_32_failure, NULL, NULL, should_run_fam_wc); } libmongoc-1.3.1/tests/test-mongoc-gridfs-file-page.c000066400000000000000000000116721264720626300223540ustar00rootroot00000000000000#include #include #include "TestSuite.h" static void test_create (void) { uint8_t fox[] = "the quick brown fox jumped over the laxy dog"; uint32_t len = sizeof fox; mongoc_gridfs_file_page_t *page; page = _mongoc_gridfs_file_page_new (fox, len, 4096); ASSERT (page); _mongoc_gridfs_file_page_destroy (page); } static void test_is_dirty (void) { uint8_t buf[] = "abcde"; uint32_t len = sizeof buf; int32_t r; mongoc_gridfs_file_page_t *page; page = _mongoc_gridfs_file_page_new (buf, len, 10); ASSERT (page); r = _mongoc_gridfs_file_page_is_dirty (page); ASSERT (!r); r = _mongoc_gridfs_file_page_write (page, "foo", 3); ASSERT (r == 3); r = _mongoc_gridfs_file_page_is_dirty (page); ASSERT (r); _mongoc_gridfs_file_page_destroy (page); } static void test_get_data (void) { uint8_t buf[] = "abcde"; uint32_t len = sizeof buf; const uint8_t *ptr; int32_t r; mongoc_gridfs_file_page_t *page; page = _mongoc_gridfs_file_page_new (buf, len, 10); ASSERT (page); ptr = _mongoc_gridfs_file_page_get_data (page); ASSERT (ptr == buf); r = _mongoc_gridfs_file_page_write (page, "foo", 3); ASSERT (r == 3); ptr = _mongoc_gridfs_file_page_get_data (page); ASSERT (ptr != buf); _mongoc_gridfs_file_page_destroy (page); } static void test_get_len (void) { uint8_t buf[] = "abcde"; uint32_t len = sizeof buf; int32_t r; mongoc_gridfs_file_page_t *page; page = _mongoc_gridfs_file_page_new (buf, len, 10); ASSERT (page); r = _mongoc_gridfs_file_page_get_len (page); ASSERT (r == 6); _mongoc_gridfs_file_page_destroy (page); } static void test_read (void) { uint8_t fox[] = "the quick brown fox jumped over the laxy dog"; uint32_t len = sizeof fox; int32_t r; char buf[100]; mongoc_gridfs_file_page_t *page; page = _mongoc_gridfs_file_page_new (fox, len, 4096); ASSERT (page); r = _mongoc_gridfs_file_page_read (page, buf, 3); ASSERT (r == 3); ASSERT (memcmp ("the", buf, 3) == 0); ASSERT (page->offset == 3); r = _mongoc_gridfs_file_page_read (page, buf, 50); ASSERT (r == len - 3); ASSERT (memcmp (fox + 3, buf, len - 3) == 0); _mongoc_gridfs_file_page_destroy (page); } static void test_seek (void) { uint8_t fox[] = "the quick brown fox jumped over the laxy dog"; uint32_t len = sizeof fox; int32_t r; mongoc_gridfs_file_page_t *page; page = _mongoc_gridfs_file_page_new (fox, len, 4096); ASSERT (page); r = _mongoc_gridfs_file_page_seek (page, 4); ASSERT (r); ASSERT (page->offset == 4); r = _mongoc_gridfs_file_page_tell (page); ASSERT (r = 4); _mongoc_gridfs_file_page_destroy (page); } static void test_write (void) { uint8_t buf[] = "abcde"; uint32_t len = sizeof buf; int32_t r; mongoc_gridfs_file_page_t *page; page = _mongoc_gridfs_file_page_new (buf, len, 10); ASSERT (page); ASSERT (page->len == len); ASSERT (!page->buf); r = _mongoc_gridfs_file_page_write (page, "1", 1); ASSERT (r == 1); ASSERT (page->buf); ASSERT (memcmp (page->buf, "1bcde", len) == 0); ASSERT (page->offset == 1); ASSERT (page->len == len); r = _mongoc_gridfs_file_page_write (page, "234567", 6); ASSERT (r == 6); ASSERT (memcmp (page->buf, "1234567", 7) == 0); ASSERT (page->offset == 7); ASSERT (page->len == 7); r = _mongoc_gridfs_file_page_write (page, "8910", 4); ASSERT (r == 3); ASSERT (memcmp (page->buf, "1234567891", 10) == 0); ASSERT (page->offset == 10); ASSERT (page->len == 10); r = _mongoc_gridfs_file_page_write (page, "foo", 3); ASSERT (r == 0); _mongoc_gridfs_file_page_destroy (page); } static void test_memset0 (void) { uint8_t buf[] = "wxyz"; uint32_t len = sizeof buf; mongoc_gridfs_file_page_t *page; page = _mongoc_gridfs_file_page_new (buf, len, 5); ASSERT (page); ASSERT (page->len == len); ASSERT (!page->buf); ASSERT (_mongoc_gridfs_file_page_memset0 (page, 1)); ASSERT (page->buf); ASSERT (memcmp (page->buf, "\0xyz", 4) == 0); ASSERT (page->offset == 1); ASSERT (_mongoc_gridfs_file_page_memset0 (page, 10)); ASSERT (page->buf); ASSERT (memcmp (page->buf, "\0\0\0\0\0", 5) == 0); ASSERT (page->offset == 5); ASSERT (_mongoc_gridfs_file_page_memset0 (page, 10)); _mongoc_gridfs_file_page_destroy (page); } void test_gridfs_file_page_install (TestSuite *suite) { TestSuite_Add (suite, "/GridFS/File/Page/create", test_create); TestSuite_Add (suite, "/GridFS/File/Page/get_data", test_get_data); TestSuite_Add (suite, "/GridFS/File/Page/get_len", test_get_len); TestSuite_Add (suite, "/GridFS/File/Page/is_dirty", test_is_dirty); TestSuite_Add (suite, "/GridFS/File/Page/read", test_read); TestSuite_Add (suite, "/GridFS/File/Page/seek", test_seek); TestSuite_Add (suite, "/GridFS/File/Page/write", test_write); TestSuite_Add (suite, "/GridFS/File/Page/memset0", test_memset0); } libmongoc-1.3.1/tests/test-mongoc-gridfs.c000066400000000000000000000545441264720626300205320ustar00rootroot00000000000000#include #define MONGOC_INSIDE #include #undef MONGOC_INSIDE #include "test-libmongoc.h" #include "mongoc-tests.h" #include "TestSuite.h" #include "test-conveniences.h" static mongoc_gridfs_t * get_test_gridfs (mongoc_client_t *client, const char *name, bson_error_t *error) { char *gen; char n [48]; gen = gen_collection_name ("fs"); bson_snprintf (n, sizeof n, "%s_%s", gen, name); bson_free (gen); return mongoc_client_get_gridfs (client, "test", n, error); } bool drop_collections (mongoc_gridfs_t *gridfs, bson_error_t *error) { return (mongoc_collection_drop (mongoc_gridfs_get_files (gridfs), error) && mongoc_collection_drop (mongoc_gridfs_get_chunks (gridfs), error)); } static void test_create (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_client_t *client; bson_error_t error; client = test_framework_client_new (); ASSERT (client); ASSERT_OR_PRINT ( (gridfs = mongoc_client_get_gridfs (client, "test", "foo", &error)), error); mongoc_gridfs_drop (gridfs, &error); file = mongoc_gridfs_create_file (gridfs, NULL); ASSERT (file); ASSERT (mongoc_gridfs_file_save (file)); mongoc_gridfs_file_destroy (file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_remove (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_gridfs_file_opt_t opts = { 0 }; mongoc_client_t *client; bson_error_t error; char name[32]; client = test_framework_client_new (); ASSERT (client); ASSERT_OR_PRINT (gridfs = mongoc_client_get_gridfs ( client, "test", "foo", &error), error); mongoc_gridfs_drop (gridfs, &error); bson_snprintf (name, sizeof name, "test-remove.%u", rand ()); opts.filename = name; file = mongoc_gridfs_create_file (gridfs, &opts); ASSERT (file); ASSERT (mongoc_gridfs_file_save (file)); ASSERT_OR_PRINT (mongoc_gridfs_file_remove (file, &error), error); mongoc_gridfs_file_destroy (file); file = mongoc_gridfs_find_one_by_filename (gridfs, name, &error); ASSERT (!file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_list (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_client_t *client; bson_error_t error; mongoc_gridfs_file_list_t *list; mongoc_gridfs_file_opt_t opt = { 0 }; bson_t query, child; char buf[100]; int i = 0; client = test_framework_client_new (); ASSERT (client); ASSERT_OR_PRINT (gridfs = get_test_gridfs (client, "list", &error), error); mongoc_gridfs_drop (gridfs, &error); for (i = 0; i < 3; i++) { bson_snprintf (buf, sizeof buf, "file.%d", i); opt.filename = buf; file = mongoc_gridfs_create_file (gridfs, &opt); ASSERT (file); ASSERT (mongoc_gridfs_file_save (file)); mongoc_gridfs_file_destroy (file); } bson_init (&query); bson_append_document_begin (&query, "$orderby", -1, &child); bson_append_int32 (&child, "filename", -1, 1); bson_append_document_end (&query, &child); bson_append_document_begin (&query, "$query", -1, &child); bson_append_document_end (&query, &child); list = mongoc_gridfs_find (gridfs, &query); bson_destroy (&query); i = 0; while ((file = mongoc_gridfs_file_list_next (list))) { bson_snprintf (buf, sizeof buf, "file.%d", i++); ASSERT_CMPINT (strcmp (mongoc_gridfs_file_get_filename (file), buf), ==, 0); mongoc_gridfs_file_destroy (file); } ASSERT_CMPINT (i, ==, 3); mongoc_gridfs_file_list_destroy (list); bson_init (&query); bson_append_utf8 (&query, "filename", -1, "file.1", -1); ASSERT_OR_PRINT (file = mongoc_gridfs_find_one (gridfs, &query, &error), error); ASSERT_CMPINT (strcmp (mongoc_gridfs_file_get_filename (file), "file.1"), ==, 0); mongoc_gridfs_file_destroy (file); ASSERT_OR_PRINT ( file = mongoc_gridfs_find_one_by_filename (gridfs, "file.1", &error), error); ASSERT_CMPINT (strcmp (mongoc_gridfs_file_get_filename (file), "file.1"), ==, 0); mongoc_gridfs_file_destroy (file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_properties (void) { mongoc_client_t *client; mongoc_gridfs_t *gridfs; bson_error_t error; bson_t *doc_in; mongoc_gridfs_file_t *file; mongoc_gridfs_file_list_t *list; bson_t query = BSON_INITIALIZER; const bson_value_t *file_id; const char *alias0, *alias1; client = test_framework_client_new (); ASSERT_OR_PRINT (gridfs = get_test_gridfs (client, "list", &error), error); mongoc_gridfs_drop (gridfs, &error); /* the C Driver sets _id to an ObjectId, but other drivers can do anything */ doc_in = BCON_NEW ( "_id", BCON_INT32 (1), "md5", BCON_UTF8 ("md5"), "filename", BCON_UTF8 ("filename"), "contentType", BCON_UTF8 ("content_type"), "aliases", "[", BCON_UTF8 ("alias0"), BCON_UTF8 ("alias1"), "]", "metadata", "{", "key", BCON_UTF8 ("value"), "}", "chunkSize", BCON_INT32 (100)); ASSERT (mongoc_collection_insert (mongoc_gridfs_get_files (gridfs), MONGOC_INSERT_NONE, doc_in, NULL, NULL)); list = mongoc_gridfs_find (gridfs, &query); file = mongoc_gridfs_file_list_next (list); file_id = mongoc_gridfs_file_get_id (file); ASSERT (file_id); ASSERT_CMPINT (BSON_TYPE_INT32, ==, file_id->value_type); ASSERT_CMPINT (1, ==, file_id->value.v_int32); ASSERT_CMPSTR ("md5", mongoc_gridfs_file_get_md5 (file)); ASSERT_CMPSTR ("filename", mongoc_gridfs_file_get_filename (file)); ASSERT_CMPSTR ("content_type", mongoc_gridfs_file_get_content_type (file)); ASSERT (BCON_EXTRACT ((bson_t *)mongoc_gridfs_file_get_aliases (file), "0", BCONE_UTF8 (alias0), "1", BCONE_UTF8 (alias1))); ASSERT_CMPSTR ("alias0", alias0); ASSERT_CMPSTR ("alias1", alias1); drop_collections (gridfs, &error); mongoc_gridfs_file_destroy (file); mongoc_gridfs_file_list_destroy (list); bson_destroy (doc_in); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_create_from_stream (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_stream_t *stream; mongoc_client_t *client; bson_error_t error; client = test_framework_client_new (); ASSERT (client); ASSERT_OR_PRINT ((gridfs = get_test_gridfs (client, "from_stream", &error)), error); mongoc_gridfs_drop (gridfs, &error); stream = mongoc_stream_file_new_for_path (BINARY_DIR"/gridfs.dat", O_RDONLY, 0); ASSERT (stream); file = mongoc_gridfs_create_file_from_stream (gridfs, stream, NULL); ASSERT (file); ASSERT (mongoc_gridfs_file_save (file)); mongoc_gridfs_file_destroy (file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_seek (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_stream_t *stream; mongoc_client_t *client; bson_error_t error; client = test_framework_client_new (); ASSERT_OR_PRINT (gridfs = get_test_gridfs (client, "seek", &error), error); mongoc_gridfs_drop (gridfs, &error); stream = mongoc_stream_file_new_for_path (BINARY_DIR"/gridfs-large.dat", O_RDONLY, 0); file = mongoc_gridfs_create_file_from_stream (gridfs, stream, NULL); ASSERT (file); ASSERT (mongoc_gridfs_file_save (file)); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, 0, SEEK_SET), ==, 0); ASSERT_CMPUINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)0); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, file->chunk_size + 1, SEEK_CUR), ==, 0); ASSERT_CMPINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)(file->chunk_size + 1)); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, 0, SEEK_END), ==, 0); ASSERT_CMPINT64 (mongoc_gridfs_file_tell (file), ==, mongoc_gridfs_file_get_length (file)); mongoc_gridfs_file_destroy (file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_read (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_stream_t *stream; mongoc_client_t *client; bson_error_t error; ssize_t r; char buf[10], buf2[10]; mongoc_iovec_t iov[2]; int previous_errno; ssize_t twenty = 20L; iov[0].iov_base = buf; iov[0].iov_len = 10; iov[1].iov_base = buf2; iov[1].iov_len = 10; client = test_framework_client_new (); ASSERT (client); ASSERT_OR_PRINT (gridfs = get_test_gridfs (client, "read", &error), error); mongoc_gridfs_drop (gridfs, &error); stream = mongoc_stream_file_new_for_path (BINARY_DIR"/gridfs-large.dat", O_RDONLY, 0); file = mongoc_gridfs_create_file_from_stream (gridfs, stream, NULL); ASSERT (file); ASSERT (mongoc_gridfs_file_save (file)); r = mongoc_gridfs_file_readv (file, iov, 2, 20, 0); ASSERT_CMPSSIZE_T (r, ==, twenty); ASSERT_MEMCMP (iov[0].iov_base, "Bacon ipsu", 10); ASSERT_MEMCMP (iov[1].iov_base, "m dolor si", 10); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, 1, SEEK_SET), ==, 0); r = mongoc_gridfs_file_readv (file, iov, 2, 20, 0); ASSERT_CMPSSIZE_T (r, ==, twenty); ASSERT_MEMCMP (iov[0].iov_base, "acon ipsum", 10); ASSERT_MEMCMP (iov[1].iov_base, " dolor sit", 10); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, file->chunk_size-1, SEEK_SET), ==, 0); r = mongoc_gridfs_file_readv (file, iov, 2, 20, 0); ASSERT_CMPSSIZE_T (r, ==, twenty); ASSERT_CMPINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)(file->chunk_size+19)); ASSERT_MEMCMP (iov[0].iov_base, "turducken ", 10); ASSERT_MEMCMP (iov[1].iov_base, "spare ribs", 10); assert (mongoc_gridfs_file_seek (file, 20, SEEK_END) == 0); previous_errno = errno; r = mongoc_gridfs_file_readv (file, iov, 2, 20, 0); assert (errno == previous_errno); assert (r == 0); assert (mongoc_gridfs_file_tell (file) == file->length + 20); mongoc_gridfs_file_destroy (file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_write (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_client_t *client; bson_error_t error; ssize_t r; char buf[] = "foo bar"; char buf2[] = " baz"; char buf3[1000]; mongoc_gridfs_file_opt_t opt = { 0 }; mongoc_iovec_t iov[2]; mongoc_iovec_t riov; ssize_t len = sizeof buf + sizeof buf2 - 2; iov [0].iov_base = buf; iov [0].iov_len = sizeof (buf) - 1; iov [1].iov_base = buf2; iov [1].iov_len = sizeof (buf2) - 1; riov.iov_base = buf3; riov.iov_len = sizeof (buf3); opt.chunk_size = 2; client = test_framework_client_new (); ASSERT (client); ASSERT_OR_PRINT (gridfs = get_test_gridfs (client, "write", &error), error); mongoc_gridfs_drop (gridfs, &error); file = mongoc_gridfs_create_file (gridfs, &opt); ASSERT (file); /* Test a write across many pages */ r = mongoc_gridfs_file_writev (file, iov, 2, 0); ASSERT_CMPSSIZE_T (r, ==, len); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, 0, SEEK_SET), ==, 0); ASSERT_CMPUINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)0); r = mongoc_gridfs_file_readv (file, &riov, 1, len, 0); ASSERT_CMPSSIZE_T (r, ==, len); ASSERT_CMPINT (memcmp (buf3, "foo bar baz", len), ==, 0); /* Test a write starting and ending exactly on chunk boundaries */ ASSERT_CMPINT (mongoc_gridfs_file_seek (file, file->chunk_size, SEEK_SET), ==, 0); ASSERT_CMPUINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)(file->chunk_size)); r = mongoc_gridfs_file_writev (file, iov+1, 1, 0); ASSERT_CMPSSIZE_T (r, ==, iov[1].iov_len); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, 0, SEEK_SET), ==, 0); ASSERT_CMPUINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)0); r = mongoc_gridfs_file_readv (file, &riov, 1, len, 0); ASSERT_CMPSSIZE_T (r, ==, len); ASSERT_CMPINT (memcmp (buf3, "fo bazr baz", len), ==, 0); /* Test writing beyond the end of the file */ assert (mongoc_gridfs_file_seek (file, 5, SEEK_END) == 0); assert (mongoc_gridfs_file_tell (file) == file->length + 5); r = mongoc_gridfs_file_writev (file, iov, 2, 0); assert (r == len); assert (mongoc_gridfs_file_tell (file) == 2*len + 5); assert (file->length == 2*len + 5); assert (mongoc_gridfs_file_save (file)); assert (mongoc_gridfs_file_seek (file, 0, SEEK_SET) == 0); assert (mongoc_gridfs_file_tell (file) == 0); r = mongoc_gridfs_file_readv (file, &riov, 1, 2*len + 5, 0); assert (r == 2*len + 5); assert (memcmp (buf3, "fo bazr baz\0\0\0\0\0foo bar baz", 2*len + 5) == 0); assert (mongoc_gridfs_file_save (file)); mongoc_gridfs_file_destroy (file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_empty (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_stream_t *stream; mongoc_client_t *client; bson_error_t error; ssize_t r; char buf[2] = {'h', 'i'}; mongoc_iovec_t iov[1]; ssize_t two = 2L; iov[0].iov_base = buf; iov[0].iov_len = 2; client = test_framework_client_new (); ASSERT_OR_PRINT (gridfs = get_test_gridfs (client, "empty", &error), error); stream = mongoc_stream_file_new_for_path (BINARY_DIR"/empty.dat", O_RDONLY, 0); file = mongoc_gridfs_create_file_from_stream (gridfs, stream, NULL); ASSERT (file); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, 0, SEEK_SET), ==, 0); ASSERT_CMPUINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)0); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, 0, SEEK_CUR), ==, 0); ASSERT_CMPUINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)0); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, 0, SEEK_END), ==, 0); ASSERT_CMPUINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)0); r = mongoc_gridfs_file_writev(file, iov, 1, 0); ASSERT_CMPSSIZE_T (r, ==, two); ASSERT_CMPINT (mongoc_gridfs_file_seek (file, 0, SEEK_SET), ==, 0); ASSERT_CMPUINT64 (mongoc_gridfs_file_tell (file), ==, (uint64_t)0); r = mongoc_gridfs_file_readv(file, iov, 1, 2, 0); ASSERT_CMPSSIZE_T (r, ==, two); ASSERT_CMPINT (strncmp (buf, "hi", 2), ==, 0); mongoc_gridfs_file_destroy (file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_stream (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_client_t *client; mongoc_stream_t *stream; mongoc_stream_t *in_stream; bson_error_t error; ssize_t r; char buf[4096]; mongoc_iovec_t iov; iov.iov_base = buf; iov.iov_len = sizeof buf; client = test_framework_client_new (); ASSERT (client); ASSERT_OR_PRINT (gridfs = get_test_gridfs (client, "fs", &error), error); mongoc_gridfs_drop (gridfs, &error); in_stream = mongoc_stream_file_new_for_path (BINARY_DIR"/gridfs.dat", O_RDONLY, 0); file = mongoc_gridfs_create_file_from_stream (gridfs, in_stream, NULL); ASSERT (file); ASSERT (mongoc_gridfs_file_save (file)); stream = mongoc_stream_gridfs_new (file); r = mongoc_stream_readv (stream, &iov, 1, file->length, 0); ASSERT_CMPINT64 ((int64_t)r, ==, file->length); /* cleanup */ mongoc_stream_destroy (stream); mongoc_gridfs_file_destroy (file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } #define ASSERT_TELL(file_, position_) \ ASSERT_CMPUINT64 (mongoc_gridfs_file_tell (file_), ==, position_) static void test_long_seek (void) { const uint64_t four_mb = 4 * 1024 * 1024; mongoc_client_t *client; bson_error_t error; mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; ssize_t r; mongoc_gridfs_file_opt_t opt = { 0, "filename" }; mongoc_iovec_t iov; char buf[16 * 1024]; /* nothing special about 16k, just a buffer */ const ssize_t buflen = sizeof (buf); ssize_t written; int64_t cursor_id; int i; iov.iov_base = buf; iov.iov_len = sizeof (buf); client = test_framework_client_new (); gridfs = get_test_gridfs (client, "long_seek", &error); ASSERT_OR_PRINT (gridfs, error); mongoc_gridfs_drop (gridfs, NULL); file = mongoc_gridfs_create_file (gridfs, &opt); ASSERT (file); /* Write 20MB, enough to ensure we need many batches, below */ written = 0; while (written < 20 * 1024 * 1024) { r = mongoc_gridfs_file_writev (file, &iov, 1, 0); ASSERT_CMPSSIZE_T (r, ==, buflen); written += r; } /* new file handle */ mongoc_gridfs_file_save (file); mongoc_gridfs_file_destroy (file); file = mongoc_gridfs_find_one (gridfs, tmp_bson ("{'filename': 'filename'}"), &error); ASSERT_OR_PRINT (file, error); /* read the start of the file */ r = mongoc_gridfs_file_readv (file, &iov, 1, sizeof (buf), 0); ASSERT_CMPSSIZE_T (r, ==, buflen); ASSERT_TELL (file, (uint64_t) buflen); cursor_id = mongoc_cursor_get_id (file->cursor); /* seek forward into next batch and read, gridfs advances cursor */ i = mongoc_gridfs_file_seek (file, four_mb, SEEK_CUR); ASSERT_CMPINT (i, ==, 0); r = mongoc_gridfs_file_readv (file, &iov, 1, sizeof (buf), 0); ASSERT_CMPSSIZE_T (r, ==, buflen); ASSERT_TELL (file, four_mb + 2 * buflen); /* same as the cursor we started with */ ASSERT_CMPINT64 (cursor_id, ==, mongoc_cursor_get_id (file->cursor)); /* seek more than a batch forward, gridfs discards cursor */ i = mongoc_gridfs_file_seek (file, 3 * four_mb, SEEK_CUR); ASSERT_CMPINT (i, ==, 0); ASSERT_TELL (file, 4 * four_mb + 2 * buflen); r = mongoc_gridfs_file_readv (file, &iov, 1, sizeof (buf), 0); ASSERT_CMPSSIZE_T (r, ==, buflen); ASSERT_TELL (file, 4 * four_mb + 3 * buflen); /* new cursor, not the one we started with */ ASSERT_CMPINT64 (cursor_id, !=, mongoc_cursor_get_id (file->cursor)); mongoc_gridfs_file_destroy (file); ASSERT_OR_PRINT (drop_collections (gridfs, &error), error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_remove_by_filename (void) { mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_gridfs_file_opt_t opt = { 0 }; mongoc_client_t *client; bson_error_t error; client = test_framework_client_new (); ASSERT (client); ASSERT_OR_PRINT (gridfs = get_test_gridfs ( client, "fs_remove_by_filename", &error), error); mongoc_gridfs_drop (gridfs, &error); opt.filename = "foo_file_1.txt"; file = mongoc_gridfs_create_file (gridfs, &opt); ASSERT (file); ASSERT (mongoc_gridfs_file_save (file)); mongoc_gridfs_file_destroy (file); opt.filename = "foo_file_2.txt"; file = mongoc_gridfs_create_file (gridfs, &opt); ASSERT (file); ASSERT (mongoc_gridfs_file_save (file)); ASSERT_OR_PRINT ( mongoc_gridfs_remove_by_filename (gridfs, "foo_file_1.txt", &error), error); mongoc_gridfs_file_destroy (file); file = mongoc_gridfs_find_one_by_filename (gridfs, "foo_file_1.txt", &error); ASSERT (!file); file = mongoc_gridfs_find_one_by_filename (gridfs, "foo_file_2.txt", &error); ASSERT (file); mongoc_gridfs_file_destroy (file); drop_collections (gridfs, &error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } static void test_missing_chunk (void) { mongoc_client_t *client; bson_error_t error; mongoc_gridfs_t *gridfs; mongoc_gridfs_file_t *file; mongoc_collection_t *chunks; ssize_t r; mongoc_gridfs_file_opt_t opt = { 0, "filename" }; mongoc_iovec_t iov; char buf[16 * 1024]; /* nothing special about 16k, just a buffer */ const ssize_t buflen = sizeof (buf); ssize_t written; bool ret; iov.iov_base = buf; iov.iov_len = sizeof (buf); client = test_framework_client_new (); gridfs = get_test_gridfs (client, "long_seek", &error); ASSERT_OR_PRINT (gridfs, error); mongoc_gridfs_drop (gridfs, NULL); file = mongoc_gridfs_create_file (gridfs, &opt); ASSERT (file); /* 700k, enough to need three 255k chunks */ written = 0; while (written < 700 * 1024) { r = mongoc_gridfs_file_writev (file, &iov, 1, 0); ASSERT_CMPSSIZE_T (r, ==, buflen); written += r; } /* new file handle */ mongoc_gridfs_file_save (file); mongoc_gridfs_file_destroy (file); file = mongoc_gridfs_find_one_by_filename (gridfs, "filename", &error); ASSERT_OR_PRINT (file, error); /* chunks have n=0, 1, 2; remove the middle one */ chunks = mongoc_gridfs_get_chunks (gridfs); ret = mongoc_collection_remove (chunks, MONGOC_REMOVE_NONE, tmp_bson ("{'n': 1}"), NULL, &error); ASSERT_OR_PRINT (ret, error); /* read the file */ for (;;) { r = mongoc_gridfs_file_readv (file, &iov, 1, sizeof (buf), 0); if (r > 0) { ASSERT_CMPSSIZE_T (r, ==, buflen); } else { ASSERT (mongoc_gridfs_file_error (file, &error)); ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CHUNK_MISSING, "missing chunk number 1"); break; } } mongoc_gridfs_file_destroy (file); ASSERT_OR_PRINT (drop_collections (gridfs, &error), error); mongoc_gridfs_destroy (gridfs); mongoc_client_destroy (client); } void test_gridfs_install (TestSuite *suite) { TestSuite_Add (suite, "/GridFS/create", test_create); TestSuite_Add (suite, "/GridFS/create_from_stream", test_create_from_stream); TestSuite_Add (suite, "/GridFS/list", test_list); TestSuite_Add (suite, "/GridFS/properties", test_properties); TestSuite_Add (suite, "/GridFS/empty", test_empty); TestSuite_Add (suite, "/GridFS/read", test_read); TestSuite_Add (suite, "/GridFS/seek", test_seek); TestSuite_Add (suite, "/GridFS/stream", test_stream); TestSuite_Add (suite, "/GridFS/remove", test_remove); TestSuite_Add (suite, "/GridFS/write", test_write); TestSuite_Add (suite, "/GridFS/test_long_seek", test_long_seek); TestSuite_Add (suite, "/GridFS/remove_by_filename", test_remove_by_filename); TestSuite_Add (suite, "/GridFS/missing_chunk", test_missing_chunk); } libmongoc-1.3.1/tests/test-mongoc-list.c000066400000000000000000000023711264720626300202160ustar00rootroot00000000000000#include #include #include "TestSuite.h" static void test_mongoc_list_basic (void) { mongoc_list_t *l; l = _mongoc_list_append(NULL, (void *)1ULL); l = _mongoc_list_append(l, (void *)2ULL); l = _mongoc_list_append(l, (void *)3ULL); l = _mongoc_list_prepend(l, (void *)4ULL); ASSERT(l); ASSERT(l->next); ASSERT(l->next->next); ASSERT(l->next->next->next); ASSERT(!l->next->next->next->next); ASSERT(l->data == (void *)4ULL); ASSERT(l->next->data == (void *)1ULL); ASSERT(l->next->next->data == (void *)2ULL); ASSERT(l->next->next->next->data == (void *)3ULL); l = _mongoc_list_remove(l, (void *)4ULL); ASSERT(l->data == (void *)1ULL); ASSERT(l->next->data == (void *)2ULL); ASSERT(l->next->next->data == (void *)3ULL); l = _mongoc_list_remove(l, (void *)2ULL); ASSERT(l->data == (void *)1ULL); ASSERT(l->next->data == (void *)3ULL); ASSERT(!l->next->next); l = _mongoc_list_remove(l, (void *)1ULL); ASSERT(l->data == (void *)3ULL); ASSERT(!l->next); l = _mongoc_list_remove(l, (void *)3ULL); ASSERT(!l); _mongoc_list_destroy(l); } void test_list_install (TestSuite *suite) { TestSuite_Add (suite, "/List/Basic", test_mongoc_list_basic); } libmongoc-1.3.1/tests/test-mongoc-log.c000066400000000000000000000111501264720626300200170ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongoc-log-private.h" #include "mongoc-trace.h" #include "TestSuite.h" struct log_state { mongoc_log_func_t handler; void *data; bool trace_enabled; }; static void save_state (struct log_state *state) { _mongoc_log_get_handler (&state->handler, &state->data); state->trace_enabled = _mongoc_log_trace_is_enabled (); } static void restore_state (const struct log_state *state) { mongoc_log_set_handler (state->handler, state->data); if (state->trace_enabled) { mongoc_log_trace_enable (); } else { mongoc_log_trace_disable (); } } struct log_func_data { mongoc_log_level_t log_level; char *log_domain; char *message; }; void log_func (mongoc_log_level_t log_level, const char *log_domain, const char *message, void *user_data) { struct log_func_data *data = (struct log_func_data *)user_data; data->log_level = log_level; data->log_domain = bson_strdup (log_domain); data->message = bson_strdup (message); } static void test_mongoc_log_handler (void) { struct log_state old_state; struct log_func_data data; save_state (&old_state); mongoc_log_set_handler (log_func, &data); #pragma push_macro("MONGOC_LOG_DOMAIN") #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "my-custom-domain" MONGOC_WARNING ("warning!"); #pragma pop_macro("MONGOC_LOG_DOMAIN") ASSERT_CMPINT (data.log_level, ==, MONGOC_LOG_LEVEL_WARNING); ASSERT_CMPSTR (data.log_domain, "my-custom-domain"); ASSERT_CMPSTR (data.message, "warning!"); restore_state (&old_state); bson_free (data.log_domain); bson_free (data.message); } static void test_mongoc_log_null (void) { struct log_state old_state; save_state (&old_state); mongoc_log_set_handler (NULL, NULL); /* doesn't seg fault */ MONGOC_ERROR ("error!"); MONGOC_DEBUG ("debug!"); restore_state (&old_state); } static int should_run_trace_tests (void) { #ifdef MONGOC_TRACE return 1; #else return 0; #endif } static int should_not_run_trace_tests (void) { return !should_run_trace_tests(); } static void test_mongoc_log_trace_enabled (void *context) { struct log_state old_state; struct log_func_data data; save_state (&old_state); mongoc_log_set_handler (log_func, &data); mongoc_log_trace_enable (); TRACE("%s", "Conscript reporting!"); ASSERT_CMPINT (data.log_level, ==, MONGOC_LOG_LEVEL_TRACE); ASSERT_CONTAINS (data.message, " Conscript reporting!"); bson_free (data.log_domain); bson_free (data.message); TRACE("%s", "Awaiting orders"); ASSERT_CMPINT (data.log_level, ==, MONGOC_LOG_LEVEL_TRACE); ASSERT_CONTAINS (data.message, "Awaiting orders"); mongoc_log_trace_disable (); TRACE("%s", "For the Union"); ASSERT_CMPINT (data.log_level, ==, MONGOC_LOG_LEVEL_TRACE); ASSERT_CONTAINS (data.message, "Awaiting orders"); bson_free (data.log_domain); bson_free (data.message); mongoc_log_trace_enable (); TRACE("%s", "For home country"); ASSERT_CMPINT (data.log_level, ==, MONGOC_LOG_LEVEL_TRACE); ASSERT_CONTAINS (data.message, "For home country"); restore_state (&old_state); bson_free (data.log_domain); bson_free (data.message); } static void test_mongoc_log_trace_disabled (void *context) { struct log_state old_state; struct log_func_data data = {(mongoc_log_level_t)-1, 0, NULL}; save_state (&old_state); mongoc_log_set_handler (log_func, &data); TRACE("%s", "Conscript reporting!"); ASSERT_CMPINT (data.log_level, ==, (mongoc_log_level_t)-1); restore_state (&old_state); } void test_log_install (TestSuite *suite) { TestSuite_Add (suite, "/Log/basic", test_mongoc_log_handler); TestSuite_AddFull (suite, "/Log/trace/enabled", test_mongoc_log_trace_enabled, NULL, NULL, should_run_trace_tests); TestSuite_AddFull (suite, "/Log/trace/disabled", test_mongoc_log_trace_disabled, NULL, NULL, should_not_run_trace_tests); TestSuite_Add (suite, "/Log/null", test_mongoc_log_null); } libmongoc-1.3.1/tests/test-mongoc-matcher.c000066400000000000000000000362341264720626300206730ustar00rootroot00000000000000#include "mongoc-tests.h" #include #include #include #include "TestSuite.h" BEGIN_IGNORE_DEPRECATIONS; static void test_mongoc_matcher_basic (void) { bson_t matcher_query; bson_t *query; bson_t *to_match; bson_t *should_fail; bson_error_t error; mongoc_matcher_t *matcher; bson_init(&matcher_query); query = BCON_NEW( "city", "New York", "state", "New York", "favorite color", "blue", "name", "{", "$not", "invalid", "}", // "zip", "{", "$in", "[", BCON_INT32(11201), BCON_INT32(90210), "]", "}", "$or", "[", "{", "age", "{", "$lt", BCON_INT32(18), "}", "}", "{", "age", "{", "$gt", BCON_INT32(45), "}", "}", "]" ); matcher = mongoc_matcher_new (query, &error); assert (matcher); _mongoc_matcher_op_to_bson(matcher->optree, &matcher_query); #if 0 { char *out = bson_as_json(&matcher_query, NULL); fprintf(stderr, "bson: %s\n", out); free(out); } #endif to_match = BCON_NEW( "city", "New York", "state", "New York", "favorite color", "blue", "zip", BCON_INT32(11201), "age", BCON_INT32(65) ); assert(mongoc_matcher_match(matcher, to_match)); should_fail = BCON_NEW( "city", "New York", "state", "New York", "favorite color", "blue", "zip", BCON_INT32(99999), "age", BCON_INT32(30) ); assert(! mongoc_matcher_match(matcher, should_fail)); bson_destroy (query); bson_destroy (to_match); bson_destroy (should_fail); bson_destroy (&matcher_query); mongoc_matcher_destroy(matcher); } static void test_mongoc_matcher_array (void) { bson_t *query; bson_t *to_match; bson_t *should_fail; bson_error_t error; mongoc_matcher_t *matcher; query = BCON_NEW ("a", "[", BCON_INT32 (1), BCON_INT32 (2), "]"); matcher = mongoc_matcher_new (query, &error); assert (matcher); /* query matches itself */ assert (mongoc_matcher_match (matcher, query)); to_match = BCON_NEW ( "a", "[", BCON_INT32 (1), BCON_INT32 (2), "]", "b", "whatever" ); assert (mongoc_matcher_match (matcher, to_match)); /* query {a: [1, 2]} doesn't match {a: 1} */ should_fail = BCON_NEW ("a", BCON_INT32 (1)); assert (!mongoc_matcher_match (matcher, should_fail)); bson_destroy (should_fail); /* query {a: [1, 2]} doesn't match {a: [2, 1]} */ should_fail = BCON_NEW ("a", "[", BCON_INT32 (2), BCON_INT32 (1), "]"); assert (!mongoc_matcher_match (matcher, should_fail)); bson_destroy (should_fail); /* query {a: [1, 2]} doesn't match {a: [1, 2, 3]} */ should_fail = BCON_NEW ("a", "[", BCON_INT32 (1), BCON_INT32 (2), BCON_INT32 (3), "]"); assert (!mongoc_matcher_match (matcher, should_fail)); bson_destroy (should_fail); /* query {a: [1, 2]} doesn't match {a: [1]} */ should_fail = BCON_NEW ("a", "[", BCON_INT32 (1), "]"); assert (!mongoc_matcher_match (matcher, should_fail)); bson_destroy (to_match); mongoc_matcher_destroy (matcher); bson_destroy (query); /* empty array */ query = BCON_NEW ("a", "[", "]"); /* {a: []} matches itself */ matcher = mongoc_matcher_new (query, &error); assert (matcher); /* query {a: []} matches {a: [], b: "whatever"} */ to_match = BCON_NEW ("a", "[", "]", "b", "whatever"); assert (mongoc_matcher_match (matcher, query)); assert (mongoc_matcher_match (matcher, to_match)); /* query {a: []} doesn't match {a: [1]} */ assert (!mongoc_matcher_match (matcher, should_fail)); bson_destroy (should_fail); /* query {a: []} doesn't match empty document */ should_fail = bson_new (); assert (!mongoc_matcher_match (matcher, should_fail)); bson_destroy (should_fail); /* query {a: []} doesn't match {a: null} */ should_fail = BCON_NEW ("a", BCON_NULL); assert (!mongoc_matcher_match (matcher, should_fail)); bson_destroy (should_fail); bson_destroy (query); bson_destroy (to_match); mongoc_matcher_destroy (matcher); } typedef struct compare_check { const char *op; int32_t doc; int32_t query; bool expected; } compare_check; static void test_mongoc_matcher_compare (void) { mongoc_matcher_t *matcher; compare_check checks[] = { { "$gt", 2, 2, false }, { "$gte", 2, 2, true}, { "$lt", 2, 2, false}, { "$lte", 2, 2, true}, { "$ne", 2, 2, false}, { NULL } }; bson_t *doc; bson_t *q; int i; for (i = 0; checks [i].op; i++) { doc = BCON_NEW ("a", BCON_INT32 (checks[i].doc)); q = BCON_NEW ("a", "{", checks[i].op, BCON_INT32 (checks[i].query), "}"); matcher = mongoc_matcher_new (q, NULL); assert (matcher); assert (mongoc_matcher_match (matcher, doc) == checks[i].expected); bson_destroy (q); bson_destroy (doc); mongoc_matcher_destroy (matcher); } } typedef struct { const char *spec; const char *doc; bool match; } logic_op_test_t; static void test_mongoc_matcher_logic_ops (void) { logic_op_test_t tests[] = { {"{\"$or\": [{\"a\": 1}, {\"b\": 2}]}", "{\"a\": 1}", true}, {"{\"$or\": [{\"a\": 1}, {\"b\": 2}]}", "{\"b\": 2}", true}, {"{\"$or\": [{\"a\": 1}, {\"b\": 2}]}", "{\"a\": 3}", false}, { "{\"$or\": [{\"a\": {\"$gt\": 1}}, {\"a\": {\"$lt\": -1}}]}", "{\"a\": 3}", true }, { "{\"$or\": [{\"a\": {\"$gt\": 1}}, {\"a\": {\"$lt\": -1}}]}", "{\"a\": -2}", true }, { "{\"$or\": [{\"a\": {\"$gt\": 1}}, {\"a\": {\"$lt\": -1}}]}", "{\"a\": 0}", false }, {"{\"$and\": [{\"a\": 1}, {\"b\": 2}]}", "{\"a\": 1, \"b\": 2}", true}, {"{\"$and\": [{\"a\": 1}, {\"b\": 2}]}", "{\"a\": 1, \"b\": 1}", false}, {"{\"$and\": [{\"a\": 1}, {\"b\": 2}]}", "{\"a\": 1}", false}, {"{\"$and\": [{\"a\": 1}, {\"b\": 2}]}", "{\"b\": 2}", false}, { "{\"$and\": [{\"a\": {\"$gt\": -1}}, {\"a\": {\"$lt\": 1}}]}", "{\"a\": 0}", true }, { "{\"$and\": [{\"a\": {\"$gt\": -1}}, {\"a\": {\"$lt\": 1}}]}", "{\"a\": -2}", false }, { "{\"$and\": [{\"a\": {\"$gt\": -1}}, {\"a\": {\"$lt\": 1}}]}", "{\"a\": 1}", false }, }; int n_tests = sizeof tests / sizeof (logic_op_test_t); int i; logic_op_test_t test; bson_t *spec; bson_error_t error; mongoc_matcher_t *matcher; bson_t *doc; bool r; for (i = 0; i < n_tests; i++) { test = tests[i]; spec = bson_new_from_json ((uint8_t * )test.spec, -1, &error); if (!spec) { fprintf (stderr, "couldn't parse JSON query:\n\n%s\n\n%s\n", test.spec, error.message); abort (); } matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); doc = bson_new_from_json ((uint8_t * )test.doc, -1, &error); if (!doc) { fprintf (stderr, "couldn't parse JSON document:\n\n%s\n\n%s\n", test.doc, error.message); abort (); } r = mongoc_matcher_match (matcher, doc); if (test.match != r) { fprintf (stderr, "query:\n\n%s\n\nshould %shave matched:\n\n%s\n", test.match ? "" : "not ", test.spec, test.doc); abort (); } mongoc_matcher_destroy (matcher); bson_destroy (doc); bson_destroy (spec); } } static void test_mongoc_matcher_bad_spec (void) { bson_t *spec; bson_error_t error; mongoc_matcher_t *matcher; spec = BCON_NEW("name", "{", "$abc", "invalid", "}"); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (!matcher); BSON_ASSERT (error.domain == MONGOC_ERROR_MATCHER); BSON_ASSERT (error.code == MONGOC_ERROR_MATCHER_INVALID); bson_destroy (spec); spec = BCON_NEW("name", "{", "$or", "", "}"); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (!matcher); BSON_ASSERT (error.domain == MONGOC_ERROR_MATCHER); BSON_ASSERT (error.code == MONGOC_ERROR_MATCHER_INVALID); bson_destroy (spec); } static void test_mongoc_matcher_eq_utf8 (void) { bson_t *doc; bson_t *spec; bson_error_t error; mongoc_matcher_t *matcher; bool r; spec = BCON_NEW("hello", "world"); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); r = mongoc_matcher_match (matcher, spec); BSON_ASSERT (r); bson_destroy (spec); mongoc_matcher_destroy (matcher); spec = BCON_NEW ("hello", "world"); doc = BCON_NEW ("hello", BCON_NULL); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); r = mongoc_matcher_match (matcher, doc); BSON_ASSERT (!r); bson_destroy (spec); bson_destroy (doc); mongoc_matcher_destroy (matcher); spec = BCON_NEW ("hello", "world"); doc = BCON_NEW ("hello", BCON_UNDEFINED); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); r = mongoc_matcher_match (matcher, doc); BSON_ASSERT (!r); bson_destroy (spec); bson_destroy (doc); mongoc_matcher_destroy (matcher); } static void test_mongoc_matcher_eq_int32 (void) { bson_t *spec; bson_t *doc; bson_error_t error; mongoc_matcher_t *matcher; bool r; spec = BCON_NEW ("hello", BCON_INT32 (1234)); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); r = mongoc_matcher_match (matcher, spec); BSON_ASSERT (r); bson_destroy (spec); mongoc_matcher_destroy (matcher); spec = BCON_NEW ("hello", BCON_INT32 (1234)); doc = BCON_NEW ("hello", BCON_INT64 (1234)); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); r = mongoc_matcher_match (matcher, doc); BSON_ASSERT (r); bson_destroy (spec); bson_destroy (doc); mongoc_matcher_destroy (matcher); spec = BCON_NEW ("hello", BCON_INT32 (1234)); doc = BCON_NEW ("hello", BCON_INT64 (4321)); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); r = mongoc_matcher_match (matcher, doc); BSON_ASSERT (!r); bson_destroy (spec); bson_destroy (doc); mongoc_matcher_destroy (matcher); } static void test_mongoc_matcher_eq_int64 (void) { bson_t *spec; bson_t *doc; bson_error_t error; mongoc_matcher_t *matcher; bool r; spec = BCON_NEW ("hello", BCON_INT64 (1234)); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); r = mongoc_matcher_match (matcher, spec); BSON_ASSERT (r); bson_destroy (spec); mongoc_matcher_destroy (matcher); spec = BCON_NEW ("hello", BCON_INT64 (1234)); doc = BCON_NEW ("hello", BCON_INT64 (1234)); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); r = mongoc_matcher_match (matcher, doc); BSON_ASSERT (r); bson_destroy (spec); bson_destroy (doc); mongoc_matcher_destroy (matcher); spec = BCON_NEW ("hello", BCON_INT64 (1234)); doc = BCON_NEW ("hello", BCON_INT32 (4321)); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); r = mongoc_matcher_match (matcher, doc); BSON_ASSERT (!r); bson_destroy (spec); bson_destroy (doc); mongoc_matcher_destroy (matcher); } static void test_mongoc_matcher_eq_doc (void) { bson_t *spec; bson_t *doc; bson_error_t error; mongoc_matcher_t *matcher; /* {doc: {a: 1}} matches itself */ spec = BCON_NEW ("doc", "{", "a", BCON_INT32 (1), "}"); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); BSON_ASSERT (mongoc_matcher_match (matcher, spec)); /* {doc: {a: 1}} matches {doc: {a: 1}, foo: "whatever"} */ doc = BCON_NEW ("doc", "{", "a", BCON_INT32 (1), "}", "foo", BCON_UTF8 ("whatever")); BSON_ASSERT (mongoc_matcher_match (matcher, doc)); bson_destroy (doc); /* {doc: {a: 1}} doesn't match {doc: 1} */ doc = BCON_NEW ("doc", BCON_INT32 (1)); BSON_ASSERT (!mongoc_matcher_match (matcher, doc)); bson_destroy (doc); /* {doc: {a: 1}} doesn't match {doc: {}} */ doc = BCON_NEW ("doc", "{", "}"); BSON_ASSERT (!mongoc_matcher_match (matcher, doc)); bson_destroy (doc); /* {doc: {a: 1}} doesn't match {doc: {a: 2}} */ doc = BCON_NEW ("doc", "{", "a", BCON_INT32 (2), "}"); BSON_ASSERT (!mongoc_matcher_match (matcher, doc)); bson_destroy (doc); /* {doc: {a: 1}} doesn't match {doc: {b: 1}} */ doc = BCON_NEW ("doc", "{", "b", BCON_INT32 (1), "}"); BSON_ASSERT (!mongoc_matcher_match (matcher, doc)); bson_destroy (doc); /* {doc: {a: 1}} doesn't match {doc: {a: 1, b: 1}} */ doc = BCON_NEW ("doc", "{", "a", BCON_INT32 (1), "b", BCON_INT32 (1), "}"); BSON_ASSERT (!mongoc_matcher_match (matcher, doc)); bson_destroy (doc); /* {doc: {a: 1, b:1}} matches itself */ bson_destroy (spec); mongoc_matcher_destroy (matcher); spec = BCON_NEW ("doc", "{", "a", BCON_INT32 (1), "b", BCON_INT32 (1), "}"); matcher = mongoc_matcher_new (spec, &error); BSON_ASSERT (matcher); BSON_ASSERT (mongoc_matcher_match (matcher, spec)); /* {doc: {a: 1, b:1}} doesn't match {doc: {a: 1}} */ doc = BCON_NEW ("doc", "{", "a", BCON_INT32 (1), "}"); BSON_ASSERT (!mongoc_matcher_match (matcher, doc)); bson_destroy (spec); bson_destroy (doc); mongoc_matcher_destroy (matcher); } static void test_mongoc_matcher_in_basic (void) { mongoc_matcher_t *matcher; bson_error_t error; bool r; bson_t *spec; bson_t doc = BSON_INITIALIZER; spec = BCON_NEW ("key", "{", "$in", "[", BCON_INT32 (1), BCON_INT32 (2), BCON_INT32 (3), "]", "}"); matcher = mongoc_matcher_new (spec, &error); r = mongoc_matcher_match (matcher, &doc); ASSERT (!r); bson_reinit (&doc); bson_append_int32 (&doc, "key", 3, 1); r = mongoc_matcher_match (matcher, &doc); ASSERT (r); bson_reinit (&doc); bson_append_int32 (&doc, "key", 3, 2); r = mongoc_matcher_match (matcher, &doc); ASSERT (r); bson_reinit (&doc); bson_append_int32 (&doc, "key", 3, 3); r = mongoc_matcher_match (matcher, &doc); ASSERT (r); bson_reinit (&doc); bson_append_int32 (&doc, "key", 3, 4); r = mongoc_matcher_match (matcher, &doc); ASSERT (!r); bson_destroy (&doc); bson_destroy (spec); mongoc_matcher_destroy (matcher); } END_IGNORE_DEPRECATIONS; void test_matcher_install (TestSuite *suite) { TestSuite_Add (suite, "/Matcher/basic", test_mongoc_matcher_basic); TestSuite_Add (suite, "/Matcher/array", test_mongoc_matcher_array); TestSuite_Add (suite, "/Matcher/compare", test_mongoc_matcher_compare); TestSuite_Add (suite, "/Matcher/logic", test_mongoc_matcher_logic_ops); TestSuite_Add (suite, "/Matcher/bad_spec", test_mongoc_matcher_bad_spec); TestSuite_Add (suite, "/Matcher/eq/utf8", test_mongoc_matcher_eq_utf8); TestSuite_Add (suite, "/Matcher/eq/int32", test_mongoc_matcher_eq_int32); TestSuite_Add (suite, "/Matcher/eq/int64", test_mongoc_matcher_eq_int64); TestSuite_Add (suite, "/Matcher/eq/doc", test_mongoc_matcher_eq_doc); TestSuite_Add (suite, "/Matcher/in/basic", test_mongoc_matcher_in_basic); } libmongoc-1.3.1/tests/test-mongoc-queue.c000066400000000000000000000015401264720626300203640ustar00rootroot00000000000000#include #include #include "TestSuite.h" static void test_mongoc_queue_basic (void) { mongoc_queue_t q = MONGOC_QUEUE_INITIALIZER; _mongoc_queue_push_head(&q, (void *)1); _mongoc_queue_push_tail(&q, (void *)2); _mongoc_queue_push_head(&q, (void *)3); _mongoc_queue_push_tail(&q, (void *)4); _mongoc_queue_push_head(&q, (void *)5); ASSERT_CMPINT(_mongoc_queue_get_length(&q), ==, 5); ASSERT(_mongoc_queue_pop_head(&q) == (void *)5); ASSERT(_mongoc_queue_pop_head(&q) == (void *)3); ASSERT(_mongoc_queue_pop_head(&q) == (void *)1); ASSERT(_mongoc_queue_pop_head(&q) == (void *)2); ASSERT(_mongoc_queue_pop_head(&q) == (void *)4); ASSERT(!_mongoc_queue_pop_head(&q)); } void test_queue_install (TestSuite *suite) { TestSuite_Add (suite, "/Queue/basic", test_mongoc_queue_basic); } libmongoc-1.3.1/tests/test-mongoc-read-prefs.c000066400000000000000000000506261264720626300213010ustar00rootroot00000000000000#include #include #include "TestSuite.h" #include "mock_server/future.h" #include "mock_server/future-functions.h" #include "mock_server/mock-server.h" #include "test-conveniences.h" static bool _can_be_command (const char *query) { return (!bson_empty (tmp_bson (query))); } static void _test_op_query (const mongoc_uri_t *uri, mock_server_t *server, const char *query_in, mongoc_read_prefs_t *read_prefs, mongoc_query_flags_t expected_query_flags, const char *expected_query) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; const bson_t *doc; bson_t b = BSON_INITIALIZER; future_t *future; request_t *request; client = mongoc_client_new_from_uri (uri); collection = mongoc_client_get_collection (client, "test", "test"); mongoc_collection_set_read_prefs (collection, read_prefs); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 1, 0, tmp_bson (query_in), NULL, read_prefs); future = future_cursor_next (cursor, &doc); request = mock_server_receives_query ( server, "test.test", expected_query_flags, 0, 1, expected_query, NULL); mock_server_replies (request, MONGOC_REPLY_NONE, /* flags */ 0, /* cursorId */ 0, /* startingFrom */ 1, /* numberReturned */ "{'a': 1}"); /* mongoc_cursor_next returned true */ assert (future_get_bool (future)); request_destroy (request); future_destroy (future); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&b); } static void _test_find_command (const mongoc_uri_t *uri, mock_server_t *server, const char *query_in, mongoc_read_prefs_t *read_prefs, mongoc_query_flags_t expected_find_cmd_query_flags, const char *expected_find_cmd) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; const bson_t *doc; bson_t b = BSON_INITIALIZER; future_t *future; request_t *request; client = mongoc_client_new_from_uri (uri); collection = mongoc_client_get_collection (client, "test", "test"); mongoc_collection_set_read_prefs (collection, read_prefs); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 1, 0, tmp_bson (query_in), NULL, read_prefs); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "test", expected_find_cmd_query_flags, expected_find_cmd); mock_server_replies (request, MONGOC_REPLY_NONE, /* flags */ 0, /* cursorId */ 0, /* startingFrom */ 1, /* numberReturned */ "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'db.collection'," " 'firstBatch': [{'a': 1}]}}"); /* mongoc_cursor_next returned true */ assert (future_get_bool (future)); request_destroy (request); future_destroy (future); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&b); } static void _test_command (const mongoc_uri_t *uri, mock_server_t *server, const char *command, mongoc_read_prefs_t *read_prefs, mongoc_query_flags_t expected_query_flags, const char *expected_query) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; const bson_t *doc; bson_t b = BSON_INITIALIZER; future_t *future; request_t *request; client = mongoc_client_new_from_uri (uri); collection = mongoc_client_get_collection (client, "test", "test"); mongoc_collection_set_read_prefs (collection, read_prefs); cursor = mongoc_collection_command (collection, MONGOC_QUERY_NONE, 0, 1, 0, tmp_bson (command), NULL, read_prefs); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "test", expected_query_flags, expected_query); mock_server_replies (request, MONGOC_REPLY_NONE, /* flags */ 0, /* cursorId */ 0, /* startingFrom */ 1, /* numberReturned */ "{'a': 1}"); /* mongoc_cursor_next returned true */ assert (future_get_bool (future)); request_destroy (request); future_destroy (future); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&b); } static void _test_command_simple (const mongoc_uri_t *uri, mock_server_t *server, const char *command, mongoc_read_prefs_t *read_prefs, mongoc_query_flags_t expected_query_flags, const char *expected_query) { mongoc_client_t *client; mongoc_collection_t *collection; bson_t b = BSON_INITIALIZER; future_t *future; request_t *request; client = mongoc_client_new_from_uri (uri); collection = mongoc_client_get_collection (client, "test", "test"); mongoc_collection_set_read_prefs (collection, read_prefs); future = future_client_command_simple (client, "test", tmp_bson (command), read_prefs, NULL, NULL); request = mock_server_receives_command ( server, "test", expected_query_flags, expected_query); mock_server_replies (request, MONGOC_REPLY_NONE, /* flags */ 0, /* cursorId */ 0, /* startingFrom */ 1, /* numberReturned */ "{'ok': 1}"); /* mongoc_cursor_next returned true */ assert (future_get_bool (future)); request_destroy (request); future_destroy (future); mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&b); } typedef enum { READ_PREF_TEST_STANDALONE, READ_PREF_TEST_MONGOS, READ_PREF_TEST_PRIMARY, READ_PREF_TEST_SECONDARY, } read_pref_test_type_t; static mock_server_t * _run_server (read_pref_test_type_t test_type, int32_t max_wire_version) { mock_server_t *server; server = mock_server_new (); mock_server_run (server); switch (test_type) { case READ_PREF_TEST_STANDALONE: mock_server_auto_ismaster (server, "{'ok': 1," " 'maxWireVersion': %d," " 'ismaster': true}", max_wire_version); break; case READ_PREF_TEST_MONGOS: mock_server_auto_ismaster (server, "{'ok': 1," " 'maxWireVersion': %d," " 'ismaster': true," " 'msg': 'isdbgrid'}", max_wire_version); break; case READ_PREF_TEST_PRIMARY: mock_server_auto_ismaster (server, "{'ok': 1," " 'maxWireVersion': %d," " 'ismaster': true," " 'setName': 'rs'," " 'hosts': ['%s']}", max_wire_version, mock_server_get_host_and_port (server)); break; case READ_PREF_TEST_SECONDARY: mock_server_auto_ismaster (server, "{'ok': 1," " 'maxWireVersion': %d," " 'ismaster': false," " 'secondary': true," " 'setName': 'rs'," " 'hosts': ['%s']}", max_wire_version, mock_server_get_host_and_port (server)); break; default: fprintf (stderr, "Invalid test_type: : %d\n", test_type); abort (); } return server; } static mongoc_uri_t * _get_uri (mock_server_t *server, read_pref_test_type_t test_type) { mongoc_uri_t *uri; uri = mongoc_uri_copy (mock_server_get_uri (server)); switch (test_type) { case READ_PREF_TEST_PRIMARY: case READ_PREF_TEST_SECONDARY: mongoc_uri_set_option_as_utf8 (uri, "replicaSet", "rs"); break; case READ_PREF_TEST_STANDALONE: case READ_PREF_TEST_MONGOS: default: break; } return uri; } static void _test_read_prefs ( read_pref_test_type_t test_type, mongoc_read_prefs_t *read_prefs, const char *query_in, const char *expected_query, mongoc_query_flags_t expected_query_flags, const char *expected_find_cmd, mongoc_query_flags_t expected_find_cmd_query_flags) { mock_server_t *server; mongoc_uri_t *uri; server = _run_server (test_type, 3); uri = _get_uri (server, test_type); _test_op_query (uri, server, query_in, read_prefs, expected_query_flags, expected_query); if (_can_be_command (query_in)) { _test_command (uri, server, query_in, read_prefs, expected_query_flags, expected_query); _test_command_simple (uri, server, query_in, read_prefs, expected_query_flags, expected_query); } mock_server_destroy (server); mongoc_uri_destroy (uri); server = _run_server (test_type, 4); uri = _get_uri (server, test_type); _test_find_command (uri, server, query_in, read_prefs, expected_find_cmd_query_flags, expected_find_cmd); mock_server_destroy (server); mongoc_uri_destroy (uri); } /* test that a NULL read pref is the same as PRIMARY */ static void test_read_prefs_standalone_null (void) { _test_read_prefs ( READ_PREF_TEST_STANDALONE, NULL, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_STANDALONE, NULL, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); } static void test_read_prefs_standalone_primary (void) { mongoc_read_prefs_t *read_prefs; /* Server Selection Spec: for topology type single and server types other * than mongos, "clients MUST always set the slaveOK wire protocol flag on * reads to ensure that any server type can handle the request." * */ read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); _test_read_prefs ( READ_PREF_TEST_STANDALONE, read_prefs, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_STANDALONE, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); } static void test_read_prefs_standalone_secondary (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); _test_read_prefs ( READ_PREF_TEST_STANDALONE, read_prefs, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_STANDALONE, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); } static void test_read_prefs_standalone_tags (void) { bson_t b = BSON_INITIALIZER; mongoc_read_prefs_t *read_prefs; bson_append_utf8 (&b, "dc", 2, "ny", 2); read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY_PREFERRED); mongoc_read_prefs_add_tag (read_prefs, &b); mongoc_read_prefs_add_tag (read_prefs, NULL); _test_read_prefs ( READ_PREF_TEST_STANDALONE, read_prefs, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_STANDALONE, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); } static void test_read_prefs_primary_rsprimary (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); _test_read_prefs ( READ_PREF_TEST_PRIMARY, read_prefs, "{}", "{}", MONGOC_QUERY_NONE, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_NONE); _test_read_prefs ( READ_PREF_TEST_PRIMARY, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_NONE, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_NONE); mongoc_read_prefs_destroy (read_prefs); } static void test_read_prefs_secondary_rssecondary (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); _test_read_prefs ( READ_PREF_TEST_SECONDARY, read_prefs, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_SECONDARY, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); } /* test that a NULL read pref is the same as PRIMARY */ static void test_read_prefs_mongos_null (void) { _test_read_prefs ( READ_PREF_TEST_MONGOS, NULL, "{}", "{}", MONGOC_QUERY_NONE, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_NONE); _test_read_prefs ( READ_PREF_TEST_MONGOS, NULL, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_NONE, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_NONE); } static void test_read_prefs_mongos_primary (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{}", "{}", MONGOC_QUERY_NONE, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_NONE); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_NONE, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_NONE); mongoc_read_prefs_destroy (read_prefs); } static void test_read_prefs_mongos_secondary (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{}", "{'$query': {}, '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {}}," " '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{'a': 1}", "{'$query': {'a': 1}, '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {'a': 1}}," " '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{'$query': {'a': 1}}", "{'$query': {'a': 1}, '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {'a': 1}}," " '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); } static void test_read_prefs_mongos_secondary_preferred (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY_PREFERRED); /* $readPreference not sent, only slaveOk */ _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); } static void test_read_prefs_mongos_tags (void) { bson_t b = BSON_INITIALIZER; mongoc_read_prefs_t *read_prefs; bson_append_utf8 (&b, "dc", 2, "ny", 2); read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY_PREFERRED); mongoc_read_prefs_add_tag (read_prefs, &b); mongoc_read_prefs_add_tag (read_prefs, NULL); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{}", "{'$query': {}, '$readPreference': {'mode': 'secondaryPreferred'," " 'tags': [{'dc': 'ny'}, {}]}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {}}," " '$readPreference': {'mode': 'secondaryPreferred'," " 'tags': [{'dc': 'ny'}, {}]}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{'a': 1}", "{'$query': {'a': 1}," " '$readPreference': {'mode': 'secondaryPreferred'," " 'tags': [{'dc': 'ny'}, {}]}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {}}," " '$readPreference': {'mode': 'secondaryPreferred'," " 'tags': [{'dc': 'ny'}, {}]}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); } void test_read_prefs_install (TestSuite *suite) { TestSuite_Add (suite, "/ReadPrefs/standalone/null", test_read_prefs_standalone_null); TestSuite_Add (suite, "/ReadPrefs/standalone/primary", test_read_prefs_standalone_primary); TestSuite_Add (suite, "/ReadPrefs/standalone/secondary", test_read_prefs_standalone_secondary); TestSuite_Add (suite, "/ReadPrefs/standalone/tags", test_read_prefs_standalone_tags); TestSuite_Add (suite, "/ReadPrefs/rsprimary/primary", test_read_prefs_primary_rsprimary); TestSuite_Add (suite, "/ReadPrefs/rssecondary/secondary", test_read_prefs_secondary_rssecondary); TestSuite_Add (suite, "/ReadPrefs/mongos/null", test_read_prefs_mongos_null); TestSuite_Add (suite, "/ReadPrefs/mongos/primary", test_read_prefs_mongos_primary); TestSuite_Add (suite, "/ReadPrefs/mongos/secondary", test_read_prefs_mongos_secondary); TestSuite_Add (suite, "/ReadPrefs/mongos/secondaryPreferred", test_read_prefs_mongos_secondary_preferred); TestSuite_Add (suite, "/ReadPrefs/mongos/tags", test_read_prefs_mongos_tags); } libmongoc-1.3.1/tests/test-mongoc-rpc.c000066400000000000000000000404331264720626300200300ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "TestSuite.h" static uint8_t * get_test_file (const char *filename, size_t *length) { ssize_t len; uint8_t *buf; char real_filename[256]; int fd; bson_snprintf (real_filename, sizeof real_filename, BINARY_DIR"/%s", filename); #ifdef _WIN32 fd = _open (real_filename, O_RDONLY | _O_BINARY); #else fd = open (real_filename, O_RDONLY); #endif if (fd == -1) { fprintf(stderr, "Failed to open: %s\n", real_filename); abort(); } len = 40960; buf = (uint8_t *)bson_malloc0(len); #ifdef _WIN32 len = _read (fd, buf, (uint32_t)len); #else len = read (fd, buf, (uint32_t)len); #endif ASSERT(len > 0); *length = len; return buf; } /* * This function expects that @rpc is in HOST ENDIAN format. */ static void assert_rpc_equal (const char *filename, mongoc_rpc_t *rpc) { mongoc_array_t ar; uint8_t *data; mongoc_iovec_t *iov; size_t length; off_t off = 0; int r; int i; data = get_test_file(filename, &length); _mongoc_array_init(&ar, sizeof(mongoc_iovec_t)); /* * Gather our RPC into a series of iovec that can be compared * to the buffer from the RCP snapshot file. */ _mongoc_rpc_gather(rpc, &ar); #if 0 fprintf(stderr, "Before swabbing\n"); fprintf(stderr, "=========================\n"); mongoc_rpc_printf(rpc); #endif _mongoc_rpc_swab_to_le(rpc); #if 0 fprintf(stderr, "After swabbing\n"); fprintf(stderr, "=========================\n"); mongoc_rpc_printf(rpc); #endif for (i = 0; i < ar.len; i++) { iov = &_mongoc_array_index(&ar, mongoc_iovec_t, i); ASSERT(iov->iov_len <= (length - off)); r = memcmp(&data[off], iov->iov_base, iov->iov_len); if (r) { fprintf(stderr, "\nError iovec: %u\n", i); } ASSERT(r == 0); off += iov->iov_len; } _mongoc_array_destroy(&ar); bson_free(data); } static void test_mongoc_rpc_delete_gather (void) { mongoc_rpc_t rpc; bson_t sel; memset(&rpc, 0xFFFFFFFF, sizeof rpc); bson_init(&sel); rpc.delete_.msg_len = 0; rpc.delete_.request_id = 1234; rpc.delete_.response_to = -1; rpc.delete_.opcode = MONGOC_OPCODE_DELETE; rpc.delete_.zero = 0; rpc.delete_.collection = "test.test"; rpc.delete_.flags = MONGOC_DELETE_SINGLE_REMOVE; rpc.delete_.selector = bson_get_data(&sel); assert_rpc_equal("delete1.dat", &rpc); } static void test_mongoc_rpc_delete_scatter (void) { uint8_t *data; mongoc_rpc_t rpc; bool r; bson_t sel; size_t length; memset(&rpc, 0xFFFFFFFF, sizeof rpc); bson_init(&sel); data = get_test_file("delete1.dat", &length); r = _mongoc_rpc_scatter(&rpc, data, length); ASSERT(r); _mongoc_rpc_swab_from_le(&rpc); ASSERT_CMPINT(rpc.delete_.msg_len, ==, 39); ASSERT_CMPINT(rpc.delete_.request_id, ==, 1234); ASSERT_CMPINT(rpc.delete_.response_to, ==, -1); ASSERT_CMPINT(rpc.delete_.opcode, ==, MONGOC_OPCODE_DELETE); ASSERT_CMPINT(rpc.delete_.zero, ==, 0); ASSERT(!strcmp("test.test", rpc.delete_.collection)); ASSERT_CMPINT(rpc.delete_.flags, ==, MONGOC_DELETE_SINGLE_REMOVE); ASSERT(!memcmp(rpc.delete_.selector, bson_get_data(&sel), sel.len)); assert_rpc_equal("delete1.dat", &rpc); bson_free(data); } static void test_mongoc_rpc_get_more_gather (void) { mongoc_rpc_t rpc; memset(&rpc, 0xFFFFFFFF, sizeof rpc); rpc.get_more.msg_len = 0; rpc.get_more.request_id = 1234; rpc.get_more.response_to = -1; rpc.get_more.opcode = MONGOC_OPCODE_GET_MORE; rpc.get_more.zero = 0; rpc.get_more.collection = "test.test"; rpc.get_more.n_return = 5; rpc.get_more.cursor_id = 12345678L; assert_rpc_equal("get_more1.dat", &rpc); } static void test_mongoc_rpc_get_more_scatter (void) { uint8_t *data; mongoc_rpc_t rpc; bool r; size_t length; memset(&rpc, 0xFFFFFFFF, sizeof rpc); data = get_test_file("get_more1.dat", &length); r = _mongoc_rpc_scatter(&rpc, data, length); ASSERT(r); _mongoc_rpc_swab_from_le(&rpc); ASSERT(rpc.get_more.msg_len == 42); ASSERT(rpc.get_more.request_id == 1234); ASSERT(rpc.get_more.response_to == -1); ASSERT(rpc.get_more.opcode == MONGOC_OPCODE_GET_MORE); ASSERT(rpc.get_more.zero == 0); ASSERT(!strcmp("test.test", rpc.get_more.collection)); ASSERT(rpc.get_more.n_return == 5); ASSERT(rpc.get_more.cursor_id == 12345678); assert_rpc_equal("get_more1.dat", &rpc); bson_free(data); } static void test_mongoc_rpc_insert_gather (void) { mongoc_rpc_t rpc; mongoc_iovec_t iov[20]; bson_t b; int i; memset(&rpc, 0xFFFFFFFF, sizeof rpc); bson_init(&b); for (i = 0; i < 20; i++) { iov[i].iov_base = (void *)bson_get_data(&b); iov[i].iov_len = b.len; } rpc.insert.msg_len = 0; rpc.insert.request_id = 1234; rpc.insert.response_to = -1; rpc.insert.opcode = MONGOC_OPCODE_INSERT; rpc.insert.flags = MONGOC_INSERT_CONTINUE_ON_ERROR; rpc.insert.collection = "test.test"; rpc.insert.documents = iov; rpc.insert.n_documents = 20; assert_rpc_equal("insert1.dat", &rpc); bson_destroy(&b); } static void test_mongoc_rpc_insert_scatter (void) { bson_reader_t *reader; uint8_t *data; const bson_t *b; mongoc_rpc_t rpc; bool r; bool eof = false; size_t length; bson_t empty; int count = 0; memset(&rpc, 0xFFFFFFFF, sizeof rpc); bson_init(&empty); data = get_test_file("insert1.dat", &length); r = _mongoc_rpc_scatter(&rpc, data, length); ASSERT(r); _mongoc_rpc_swab_from_le(&rpc); ASSERT_CMPINT(rpc.insert.msg_len, ==, 130); ASSERT_CMPINT(rpc.insert.request_id, ==, 1234); ASSERT_CMPINT(rpc.insert.response_to, ==, (uint32_t)-1); ASSERT_CMPINT(rpc.insert.opcode, ==, MONGOC_OPCODE_INSERT); ASSERT_CMPINT(rpc.insert.flags, ==, MONGOC_INSERT_CONTINUE_ON_ERROR); ASSERT(!strcmp("test.test", rpc.insert.collection)); reader = bson_reader_new_from_data ((uint8_t *)rpc.insert.documents[0].iov_base, rpc.insert.documents[0].iov_len); while ((b = bson_reader_read(reader, &eof))) { r = bson_equal(b, &empty); ASSERT(r); count++; } ASSERT(eof == true); ASSERT(count == 20); assert_rpc_equal("insert1.dat", &rpc); bson_free(data); bson_reader_destroy(reader); bson_destroy(&empty); } static void test_mongoc_rpc_kill_cursors_gather (void) { mongoc_rpc_t rpc; int64_t cursors[] = { 1, 2, 3, 4, 5 }; memset(&rpc, 0xFFFFFFFF, sizeof rpc); rpc.kill_cursors.msg_len = 0; rpc.kill_cursors.request_id = 1234; rpc.kill_cursors.response_to = -1; rpc.kill_cursors.opcode = MONGOC_OPCODE_KILL_CURSORS; rpc.kill_cursors.zero = 0; rpc.kill_cursors.n_cursors = 5; rpc.kill_cursors.cursors = cursors; assert_rpc_equal("kill_cursors1.dat", &rpc); } static void test_mongoc_rpc_kill_cursors_scatter (void) { uint8_t *data; const int64_t cursors[] = { 1, 2, 3, 4, 5 }; mongoc_rpc_t rpc; bool r; size_t length; memset(&rpc, 0xFFFFFFFF, sizeof rpc); data = get_test_file("kill_cursors1.dat", &length); r = _mongoc_rpc_scatter(&rpc, data, length); ASSERT(r); _mongoc_rpc_swab_from_le(&rpc); ASSERT_CMPINT(rpc.kill_cursors.msg_len, ==, 64); ASSERT_CMPINT(rpc.kill_cursors.request_id, ==, 1234); ASSERT_CMPINT(rpc.kill_cursors.response_to, ==, -1); ASSERT_CMPINT(rpc.kill_cursors.opcode, ==, MONGOC_OPCODE_KILL_CURSORS); ASSERT_CMPINT(rpc.kill_cursors.zero, ==, 0); ASSERT_CMPINT(rpc.kill_cursors.n_cursors, ==, 5); ASSERT(!memcmp(rpc.kill_cursors.cursors, cursors, 5 * 8)); assert_rpc_equal("kill_cursors1.dat", &rpc); bson_free(data); } static void test_mongoc_rpc_msg_gather (void) { mongoc_rpc_t rpc; memset(&rpc, 0xFFFFFFFF, sizeof rpc); rpc.msg.msg_len = 0; rpc.msg.request_id = 1234; rpc.msg.response_to = -1; rpc.msg.opcode = MONGOC_OPCODE_MSG; rpc.msg.msg = "this is a test message."; assert_rpc_equal("msg1.dat", &rpc); } static void test_mongoc_rpc_msg_scatter (void) { uint8_t *data; mongoc_rpc_t rpc; bool r; size_t length; memset(&rpc, 0xFFFFFFFF, sizeof rpc); data = get_test_file("msg1.dat", &length); r = _mongoc_rpc_scatter(&rpc, data, length); ASSERT(r); _mongoc_rpc_swab_from_le(&rpc); ASSERT(rpc.msg.msg_len == 40); ASSERT(rpc.msg.request_id == 1234); ASSERT(rpc.msg.response_to == -1); ASSERT(rpc.msg.opcode == MONGOC_OPCODE_MSG); ASSERT(!strcmp(rpc.msg.msg, "this is a test message.")); assert_rpc_equal("msg1.dat", &rpc); bson_free(data); } static void test_mongoc_rpc_query_gather (void) { mongoc_rpc_t rpc; bson_t b; memset(&rpc, 0xFFFFFFFF, sizeof rpc); bson_init(&b); rpc.query.msg_len = 0; rpc.query.request_id = 1234; rpc.query.response_to = -1; rpc.query.opcode = MONGOC_OPCODE_QUERY; rpc.query.flags = MONGOC_QUERY_SLAVE_OK; rpc.query.collection = "test.test"; rpc.query.skip = 5; rpc.query.n_return = 1; rpc.query.query = bson_get_data(&b); rpc.query.fields = bson_get_data(&b); assert_rpc_equal("query1.dat", &rpc); } static void test_mongoc_rpc_query_scatter (void) { uint8_t *data; mongoc_rpc_t rpc; bool r; bson_t empty; size_t length; bson_init(&empty); memset(&rpc, 0xFFFFFFFF, sizeof rpc); data = get_test_file("query1.dat", &length); r = _mongoc_rpc_scatter(&rpc, data, length); ASSERT(r); _mongoc_rpc_swab_from_le(&rpc); ASSERT(rpc.query.msg_len == 48); ASSERT(rpc.query.request_id == 1234); ASSERT(rpc.query.response_to == (uint32_t)-1); ASSERT(rpc.query.opcode == MONGOC_OPCODE_QUERY); ASSERT(rpc.query.flags == MONGOC_QUERY_SLAVE_OK); ASSERT(!strcmp(rpc.query.collection, "test.test")); ASSERT(rpc.query.skip == 5); ASSERT(rpc.query.n_return == 1); ASSERT(!memcmp(rpc.query.query, bson_get_data(&empty), 5)); ASSERT(!memcmp(rpc.query.fields, bson_get_data(&empty), 5)); assert_rpc_equal("query1.dat", &rpc); bson_free(data); } static void test_mongoc_rpc_reply_gather (void) { bson_writer_t *writer; mongoc_rpc_t rpc; uint8_t *buf = NULL; size_t len = 0; bson_t *b; int i; memset(&rpc, 0xFFFFFFFF, sizeof rpc); writer = bson_writer_new (&buf, &len, 0, bson_realloc_ctx, NULL); for (i = 0; i < 100; i++) { bson_writer_begin(writer, &b); bson_writer_end(writer); } rpc.reply.msg_len = 0; rpc.reply.request_id = 1234; rpc.reply.response_to = -1; rpc.reply.opcode = MONGOC_OPCODE_REPLY; rpc.reply.flags = MONGOC_REPLY_AWAIT_CAPABLE; rpc.reply.cursor_id = 12345678; rpc.reply.start_from = 50; rpc.reply.n_returned = 100; rpc.reply.documents = buf; rpc.reply.documents_len = (int32_t)bson_writer_get_length(writer); assert_rpc_equal("reply1.dat", &rpc); bson_writer_destroy(writer); bson_free(buf); } static void test_mongoc_rpc_reply_scatter (void) { bson_reader_t *reader; uint8_t *data; mongoc_rpc_t rpc; const bson_t *b; bool r; bool eof = false; bson_t empty; size_t length; int count = 0; bson_init(&empty); memset(&rpc, 0xFFFFFFFF, sizeof rpc); data = get_test_file("reply1.dat", &length); r = _mongoc_rpc_scatter(&rpc, data, length); ASSERT(r); _mongoc_rpc_swab_from_le(&rpc); ASSERT_CMPINT(rpc.reply.msg_len, ==, 536); ASSERT_CMPINT(rpc.reply.request_id, ==, 1234); ASSERT_CMPINT(rpc.reply.response_to, ==, -1); ASSERT_CMPINT(rpc.reply.opcode, ==, MONGOC_OPCODE_REPLY); ASSERT_CMPINT(rpc.reply.flags, ==, MONGOC_REPLY_AWAIT_CAPABLE); ASSERT(rpc.reply.cursor_id == 12345678LL); ASSERT_CMPINT(rpc.reply.start_from, ==, 50); ASSERT_CMPINT(rpc.reply.n_returned, ==, 100); ASSERT_CMPINT(rpc.reply.documents_len, ==, 500); reader = bson_reader_new_from_data(rpc.reply.documents, rpc.reply.documents_len); while ((b = bson_reader_read(reader, &eof))) { r = bson_equal(b, &empty); ASSERT(r); count++; } ASSERT(eof == true); ASSERT(count == 100); assert_rpc_equal("reply1.dat", &rpc); bson_reader_destroy(reader); bson_free(data); } static void test_mongoc_rpc_reply_scatter2 (void) { bson_reader_t *reader; uint8_t *data; mongoc_rpc_t rpc; const bson_t *b; bool r; bool eof = false; bson_t empty; size_t length; int count = 0; bson_init(&empty); memset(&rpc, 0xFFFFFFFF, sizeof rpc); data = get_test_file("reply2.dat", &length); r = _mongoc_rpc_scatter(&rpc, data, length); ASSERT(r); _mongoc_rpc_swab_from_le(&rpc); ASSERT(rpc.reply.msg_len == 16236); ASSERT(rpc.reply.request_id == 0); ASSERT(rpc.reply.response_to == 1234); ASSERT(rpc.reply.opcode == MONGOC_OPCODE_REPLY); ASSERT(rpc.reply.flags == 0); ASSERT(rpc.reply.cursor_id == 12345678); ASSERT(rpc.reply.start_from == 0); ASSERT(rpc.reply.n_returned == 100); ASSERT(rpc.reply.documents_len == 16200); reader = bson_reader_new_from_data(rpc.reply.documents, rpc.reply.documents_len); while ((b = bson_reader_read(reader, &eof))) { count++; } ASSERT(eof == true); ASSERT(count == 100); assert_rpc_equal("reply2.dat", &rpc); bson_reader_destroy(reader); bson_free(data); } static void test_mongoc_rpc_update_gather (void) { mongoc_rpc_t rpc; bson_t sel; bson_t up; memset(&rpc, 0xFFFFFFFF, sizeof rpc); bson_init(&sel); bson_init(&up); rpc.update.msg_len = 0; rpc.update.request_id = 1234; rpc.update.response_to = -1; rpc.update.opcode = MONGOC_OPCODE_UPDATE; rpc.update.zero = 0; rpc.update.collection = "test.test"; rpc.update.flags = MONGOC_UPDATE_MULTI_UPDATE; rpc.update.selector = bson_get_data(&sel); rpc.update.update = bson_get_data(&up); assert_rpc_equal("update1.dat", &rpc); } static void test_mongoc_rpc_update_scatter (void) { uint8_t *data; mongoc_rpc_t rpc; bool r; bson_t b; bson_t empty; size_t length; int32_t len; bson_init(&empty); memset(&rpc, 0xFFFFFFFF, sizeof rpc); data = get_test_file("update1.dat", &length); r = _mongoc_rpc_scatter(&rpc, data, length); ASSERT(r); _mongoc_rpc_swab_from_le(&rpc); ASSERT_CMPINT(rpc.update.msg_len, ==, 44); ASSERT_CMPINT(rpc.update.request_id, ==, 1234); ASSERT_CMPINT(rpc.update.response_to, ==, -1); ASSERT_CMPINT(rpc.update.opcode, ==, MONGOC_OPCODE_UPDATE); ASSERT_CMPINT(rpc.update.flags, ==, MONGOC_UPDATE_MULTI_UPDATE); ASSERT(!strcmp(rpc.update.collection, "test.test")); memcpy(&len, rpc.update.selector, 4); len = BSON_UINT32_FROM_LE(len); ASSERT(len > 4); r = bson_init_static(&b, rpc.update.selector, len); ASSERT(r); r = bson_equal(&b, &empty); ASSERT(r); bson_destroy(&b); memcpy(&len, rpc.update.update, 4); len = BSON_UINT32_FROM_LE(len); ASSERT(len > 4); r = bson_init_static(&b, rpc.update.update, len); ASSERT(r); r = bson_equal(&b, &empty); ASSERT(r); bson_destroy(&b); assert_rpc_equal("update1.dat", &rpc); bson_free(data); } void test_rpc_install (TestSuite *suite) { TestSuite_Add (suite, "/Rpc/delete/gather", test_mongoc_rpc_delete_gather); TestSuite_Add (suite, "/Rpc/delete/scatter", test_mongoc_rpc_delete_scatter); TestSuite_Add (suite, "/Rpc/get_more/gather", test_mongoc_rpc_get_more_gather); TestSuite_Add (suite, "/Rpc/get_more/scatter", test_mongoc_rpc_get_more_scatter); TestSuite_Add (suite, "/Rpc/insert/gather", test_mongoc_rpc_insert_gather); TestSuite_Add (suite, "/Rpc/insert/scatter", test_mongoc_rpc_insert_scatter); TestSuite_Add (suite, "/Rpc/kill_cursors/gather", test_mongoc_rpc_kill_cursors_gather); TestSuite_Add (suite, "/Rpc/kill_cursors/scatter", test_mongoc_rpc_kill_cursors_scatter); TestSuite_Add (suite, "/Rpc/msg/gather", test_mongoc_rpc_msg_gather); TestSuite_Add (suite, "/Rpc/msg/scatter", test_mongoc_rpc_msg_scatter); TestSuite_Add (suite, "/Rpc/query/gather", test_mongoc_rpc_query_gather); TestSuite_Add (suite, "/Rpc/query/scatter", test_mongoc_rpc_query_scatter); TestSuite_Add (suite, "/Rpc/reply/gather", test_mongoc_rpc_reply_gather); TestSuite_Add (suite, "/Rpc/reply/scatter", test_mongoc_rpc_reply_scatter); TestSuite_Add (suite, "/Rpc/reply/scatter2", test_mongoc_rpc_reply_scatter2); TestSuite_Add (suite, "/Rpc/update/gather", test_mongoc_rpc_update_gather); TestSuite_Add (suite, "/Rpc/update/scatter", test_mongoc_rpc_update_scatter); } libmongoc-1.3.1/tests/test-mongoc-sdam.c000066400000000000000000000204151264720626300201660ustar00rootroot00000000000000#include #include #include #include "json-test.h" #include "mongoc-client-private.h" #include "mongoc-server-description-private.h" #include "mongoc-topology-description-private.h" #include "mongoc-topology-private.h" #include "mongoc-util-private.h" #include "TestSuite.h" #include "test-conveniences.h" #include #include #ifdef _MSC_VER #define PATH_MAX 1024 #define realpath(path, expanded) GetFullPathName(path, PATH_MAX, expanded, NULL) #endif #define MAX_NUM_TESTS 100 /* caller must clean up the returned description */ static mongoc_server_description_t * _server_description_by_hostname(mongoc_topology_description_t *topology, const char *address) { mongoc_set_t *set = topology->servers; mongoc_server_description_t *server_iter; int i; for (i = 0; i < set->items_len; i++) { server_iter = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, i); if (strcasecmp(address, server_iter->connection_address) == 0) { return server_iter; } } return NULL; } static void _topology_has_description(mongoc_topology_description_t *topology, bson_t *server, const char *address) { mongoc_server_description_t *sd; bson_iter_t server_iter; const char *set_name; sd = _server_description_by_hostname(topology, address); assert (sd); bson_iter_init(&server_iter, server); while (bson_iter_next (&server_iter)) { if (strcmp("setName", bson_iter_key (&server_iter)) == 0) { set_name = bson_iter_utf8(&server_iter, NULL); if (set_name) { assert (sd->set_name); ASSERT_CMPSTR (sd->set_name, set_name); } } else if (strcmp("type", bson_iter_key (&server_iter)) == 0) { assert (sd->type == server_type_from_test(bson_iter_utf8(&server_iter, NULL))); } else if (strcmp("setVersion", bson_iter_key (&server_iter)) == 0) { int64_t expected_set_version; if (BSON_ITER_HOLDS_NULL (&server_iter)) { expected_set_version = MONGOC_NO_SET_VERSION; } else { expected_set_version = bson_iter_as_int64 (&server_iter); } assert (sd->set_version == expected_set_version); } else if (strcmp("electionId", bson_iter_key (&server_iter)) == 0) { bson_oid_t expected_oid; if (BSON_ITER_HOLDS_NULL (&server_iter)) { bson_oid_init_from_string (&expected_oid, "000000000000000000000000"); } else { ASSERT (BSON_ITER_HOLDS_OID (&server_iter)); bson_oid_copy (bson_iter_oid (&server_iter), &expected_oid); } ASSERT_CMPOID (&sd->election_id, &expected_oid); } else { fprintf (stderr, "ERROR: unparsed field %s\n", bson_iter_key(&server_iter)); assert (0); } } } /* *----------------------------------------------------------------------- * * Run the JSON tests from the Server Discovery and Monitoring spec. * *----------------------------------------------------------------------- */ static void test_sdam_cb (bson_t *test) { mongoc_server_description_t *sd; mongoc_client_t *client; bson_error_t error; bson_t ismasters; bson_t phase; bson_t phases; bson_t ismaster; bson_t response; bson_t servers; bson_t server; bson_t outcome; bson_iter_t phase_iter; bson_iter_t phase_field_iter; bson_iter_t ismaster_iter; bson_iter_t ismaster_field_iter; bson_iter_t servers_iter; bson_iter_t outcome_iter; bson_iter_t iter; const char *set_name; const char *hostname; /* parse out the uri and use it to create a client */ assert (bson_iter_init_find(&iter, test, "uri")); client = mongoc_client_new(bson_iter_utf8(&iter, NULL)); /* for each phase, parse and validate */ assert (bson_iter_init_find(&iter, test, "phases")); bson_iter_bson (&iter, &phases); bson_iter_init (&phase_iter, &phases); while (bson_iter_next (&phase_iter)) { bson_iter_bson (&phase_iter, &phase); /* grab ismaster responses out and feed them to topology */ assert (bson_iter_init_find(&phase_field_iter, &phase, "responses")); bson_iter_bson (&phase_field_iter, &ismasters); bson_iter_init (&ismaster_iter, &ismasters); while (bson_iter_next (&ismaster_iter)) { bson_iter_bson (&ismaster_iter, &ismaster); /* fetch server description for this server based on its hostname */ bson_iter_init_find (&ismaster_field_iter, &ismaster, "0"); sd = _server_description_by_hostname(&client->topology->description, bson_iter_utf8(&ismaster_field_iter, NULL)); /* if server has been removed from topology, skip */ /* TODO: ASSURE that the manager has the same behavior */ if (!sd) continue; bson_iter_init_find (&ismaster_field_iter, &ismaster, "1"); bson_iter_bson (&ismaster_field_iter, &response); /* send ismaster through the topology description's handler */ mongoc_topology_description_handle_ismaster(&client->topology->description, sd, &response, 15, &error); } /* parse out "outcome" and validate */ assert (bson_iter_init_find(&phase_field_iter, &phase, "outcome")); bson_iter_bson (&phase_field_iter, &outcome); bson_iter_init (&outcome_iter, &outcome); while (bson_iter_next (&outcome_iter)) { if (strcmp ("servers", bson_iter_key (&outcome_iter)) == 0) { bson_iter_bson (&outcome_iter, &servers); ASSERT_CMPINT ( bson_count_keys (&servers), ==, (int) client->topology->description.servers->items_len); bson_iter_init (&servers_iter, &servers); /* for each server, ensure topology has a matching entry */ while (bson_iter_next (&servers_iter)) { hostname = bson_iter_key (&servers_iter); bson_iter_bson (&servers_iter, &server); _topology_has_description(&client->topology->description, &server, hostname); } } else if (strcmp ("setName", bson_iter_key (&outcome_iter)) == 0) { set_name = bson_iter_utf8(&outcome_iter, NULL); if (set_name) { assert (&client->topology->description.set_name); ASSERT_CMPSTR (client->topology->description.set_name, set_name); } } else if (strcmp ("topologyType", bson_iter_key (&outcome_iter)) == 0) { ASSERT_CMPSTR ( topology_type_to_string(client->topology->description.type), bson_iter_utf8(&outcome_iter, NULL)); } else { fprintf (stderr, "ERROR: unparsed test field %s\n", bson_iter_key (&outcome_iter)); assert (false); } } } mongoc_client_destroy (client); } /* *----------------------------------------------------------------------- * * Runner for the JSON tests for server discovery and monitoring.. * *----------------------------------------------------------------------- */ static void test_all_spec_tests (TestSuite *suite) { char resolved[PATH_MAX]; /* Single */ if (realpath ("tests/json/server_discovery_and_monitoring/single", resolved)) { install_json_test_suite(suite, resolved, &test_sdam_cb); } /* Replica set */ if (realpath ("tests/json/server_discovery_and_monitoring/rs", resolved)) { install_json_test_suite(suite, resolved, &test_sdam_cb); } /* Sharded */ if (realpath ("tests/json/server_discovery_and_monitoring/sharded", resolved)) { install_json_test_suite(suite, resolved, &test_sdam_cb); } /* Tests not in official Server Discovery And Monitoring Spec */ if (realpath ("tests/json/server_discovery_and_monitoring/supplemental", resolved)) { install_json_test_suite(suite, resolved, &test_sdam_cb); } } void test_sdam_install (TestSuite *suite) { test_all_spec_tests(suite); } libmongoc-1.3.1/tests/test-mongoc-server-selection-errors.c000066400000000000000000000076461264720626300240600ustar00rootroot00000000000000#include #include "TestSuite.h" #include "test-conveniences.h" #include "test-libmongoc.h" static void server_selection_error_dns (const char *uri, const char *errmsg, bool assert_as) { mongoc_client_t *client; mongoc_collection_t *collection; bson_error_t error; bson_t *command; bson_t reply; bool success; client = mongoc_client_new (uri); collection = mongoc_client_get_collection (client, "test", "test"); command = tmp_bson("{'ping': 1}"); success = mongoc_collection_command_simple (collection, command, NULL, &reply, &error); ASSERT_OR_PRINT(success == assert_as, error); if (!success && errmsg) { ASSERT_CMPSTR(error.message, errmsg); } bson_destroy (&reply); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_server_selection_error_dns_single (void) { server_selection_error_dns ( "mongodb://non-existing-localhost:27017/", "No suitable servers found (`serverselectiontryonce` set): [Failed to resolve 'non-existing-localhost']", false ); } static void test_server_selection_error_dns_multi_fail (void) { server_selection_error_dns ( "mongodb://non-existing-localhost:27017,other-non-existing-localhost:27017/", "No suitable servers found (`serverselectiontryonce` set): [Failed to resolve 'non-existing-localhost'] [Failed to resolve 'other-non-existing-localhost']", false ); } static void test_server_selection_error_dns_multi_success (void *context) { char *uri_str; uri_str = bson_strdup_printf ( "mongodb://non-existing-localhost:27017," "%s:%d," "other-non-existing-localhost:27017/", test_framework_get_host (), test_framework_get_port ()); server_selection_error_dns (uri_str, "", true); bson_free (uri_str); } static void test_server_selection_uds_auth_failure (void *context) { mongoc_client_t *client; bson_error_t error; bson_t reply; char *path; char *uri; path = test_framework_get_unix_domain_socket_path (); uri = bson_strdup_printf ("mongodb://user:wrongpass@%s", path); client = mongoc_client_new (uri); test_framework_set_ssl_opts (client); assert (client); ASSERT_OR_PRINT (! mongoc_client_get_server_status (client, NULL, &reply, &error), error); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_CLIENT); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_CLIENT_AUTHENTICATE); bson_destroy (&reply); bson_free (path); bson_free (uri); mongoc_client_destroy (client); } static void test_server_selection_uds_not_found (void *context) { mongoc_client_t *client; bson_error_t error; bson_t reply; client = mongoc_client_new ("mongodb:///tmp/mongodb-so-close.sock"); test_framework_set_ssl_opts (client); assert (client); ASSERT_OR_PRINT (! mongoc_client_get_server_status (client, NULL, &reply, &error), error); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_SERVER_SELECTION); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_SERVER_SELECTION_FAILURE); bson_destroy (&reply); mongoc_client_destroy (client); } void test_server_selection_errors_install (TestSuite *suite) { TestSuite_Add (suite, "/server_selection/errors/dns/single", test_server_selection_error_dns_single); TestSuite_Add (suite, "/server_selection/errors/dns/multi/fail", test_server_selection_error_dns_multi_fail); TestSuite_AddFull (suite, "/server_selection/errors/dns/multi/success", test_server_selection_error_dns_multi_success, NULL, NULL, test_framework_skip_if_single); TestSuite_AddFull (suite, "/server_selection/errors/uds/auth_failure", test_server_selection_uds_auth_failure, NULL, NULL, test_framework_skip_if_windows); TestSuite_AddFull (suite, "/server_selection/errors/uds/not_found", test_server_selection_uds_not_found, NULL, NULL, test_framework_skip_if_windows); } libmongoc-1.3.1/tests/test-mongoc-server-selection.c000066400000000000000000000201441264720626300225320ustar00rootroot00000000000000#include #include #include "json-test.h" #include "mongoc-server-description-private.h" #include "mongoc-topology-description-private.h" #include "mongoc-topology-private.h" #include "TestSuite.h" #include "test-conveniences.h" #ifdef _MSC_VER #define PATH_MAX 1024 #define realpath(path, expanded) GetFullPathName(path, PATH_MAX, expanded, NULL) #endif #include #include static mongoc_ss_optype_t optype_from_test(const char *op) { if (strcmp(op, "read") == 0) { return MONGOC_SS_READ; } else if (strcmp(op, "write") == 0) { return MONGOC_SS_WRITE; } return 0; } static mongoc_read_mode_t read_mode_from_test(const char *mode) { if (strcmp(mode, "Primary") == 0) { return MONGOC_READ_PRIMARY; } else if (strcmp(mode, "PrimaryPreferred") == 0) { return MONGOC_READ_PRIMARY_PREFERRED; } else if (strcmp(mode, "Secondary") == 0) { return MONGOC_READ_SECONDARY; } else if (strcmp(mode, "SecondaryPreferred") == 0) { return MONGOC_READ_SECONDARY_PREFERRED; } else if (strcmp(mode, "Nearest") == 0) { return MONGOC_READ_NEAREST; } return 0; } /* *----------------------------------------------------------------------- * * test_rtt_calculation_cb -- * * Runs the JSON tests for RTT calculation included with the * Server Selection spec. * *----------------------------------------------------------------------- */ static void test_rtt_calculation_cb (bson_t *test) { mongoc_server_description_t *description; bson_iter_t iter; BSON_ASSERT (test); description = (mongoc_server_description_t *)bson_malloc0(sizeof *description); mongoc_server_description_init(description, "localhost:27017", 1); /* parse RTT into server description */ assert(bson_iter_init_find(&iter, test, "avg_rtt_ms")); description->round_trip_time = bson_iter_int64(&iter); /* update server description with new rtt */ assert(bson_iter_init_find(&iter, test, "new_rtt_ms")); mongoc_server_description_update_rtt(description, bson_iter_int64(&iter)); /* ensure new RTT was calculated correctly */ assert(bson_iter_init_find(&iter, test, "new_avg_rtt")); assert(description->round_trip_time == bson_iter_int64(&iter)); mongoc_server_description_destroy(description); } /* *----------------------------------------------------------------------- * * test_server_selection_logic_cb -- * * Runs the JSON tests for server selection logic that are * included with the Server Selection spec. * *----------------------------------------------------------------------- */ static void test_server_selection_logic_cb (bson_t *test) { mongoc_topology_description_t topology; mongoc_server_description_t *sd; mongoc_read_prefs_t *read_prefs; mongoc_read_mode_t read_mode; mongoc_ss_optype_t op; bson_iter_t iter; bson_iter_t topology_iter; bson_iter_t server_iter; bson_iter_t sd_iter; bson_iter_t sd_child_iter; bson_iter_t read_pref_iter; bson_t test_topology; bson_t test_servers; bson_t server; bson_t candidates; bson_t eligible; bson_t suitable; bson_t latency; bson_t test_read_pref; bson_t test_tags; const char *type; int j = 0; mongoc_array_t selected_servers; BSON_ASSERT (test); /* pull out topology description field */ assert(bson_iter_init_find(&iter, test, "topology_description")); bson_iter_bson (&iter, &test_topology); /* set topology state from test */ assert(bson_iter_init_find(&topology_iter, &test_topology, "type")); type = bson_iter_utf8(&topology_iter, NULL); if (strcmp(type, "Single") == 0) { mongoc_topology_description_init(&topology, MONGOC_TOPOLOGY_SINGLE); } else { mongoc_topology_description_init(&topology, MONGOC_TOPOLOGY_UNKNOWN); topology.type = topology_type_from_test(bson_iter_utf8(&topology_iter, NULL)); } /* for each server description in test, add server to our topology */ assert(bson_iter_init_find(&topology_iter, &test_topology, "servers")); bson_iter_bson (&topology_iter, &test_servers); bson_iter_init(&server_iter, &test_servers); while (bson_iter_next (&server_iter)) { bson_iter_bson (&server_iter, &server); /* initialize new server description with given address */ sd = (mongoc_server_description_t *)bson_malloc0(sizeof *sd); assert(bson_iter_init_find(&sd_iter, &server, "address")); mongoc_server_description_init(sd, bson_iter_utf8(&sd_iter, NULL), j++); /* set description rtt */ assert(bson_iter_init_find(&sd_iter, &server, "avg_rtt_ms")); sd->round_trip_time = bson_iter_int32(&sd_iter); /* set description type */ assert(bson_iter_init_find(&sd_iter, &server, "type")); sd->type = server_type_from_test(bson_iter_utf8(&sd_iter, NULL)); /* set description tags */ /* TODO FIX ONCE ARRAYS OF TAG SETS GO AWAY IN TESTS */ assert(bson_iter_init_find(&sd_iter, &server, "tags")); bson_iter_recurse(&sd_iter, &sd_child_iter); bson_iter_next(&sd_child_iter); bson_iter_bson (&sd_child_iter, &sd->tags); /* add new server to our topology description */ mongoc_set_add(topology.servers, sd->id, sd); } /* create read preference document from test */ assert (bson_iter_init_find(&iter, test, "read_preference")); bson_iter_bson (&iter, &test_read_pref); assert (bson_iter_init_find(&read_pref_iter, &test_read_pref, "mode")); read_mode = read_mode_from_test (bson_iter_utf8 (&read_pref_iter, NULL)); ASSERT (read_mode != 0); read_prefs = mongoc_read_prefs_new (read_mode); assert (bson_iter_init_find(&read_pref_iter, &test_read_pref, "tags")); bson_iter_bson (&read_pref_iter, &test_tags); mongoc_read_prefs_set_tags(read_prefs, &test_tags); /* get optype */ assert (bson_iter_init_find(&iter, test, "operation")); op = optype_from_test(bson_iter_utf8(&iter, NULL)); ASSERT(op != 0); /* read in candidate servers */ assert (bson_iter_init_find(&iter, test, "candidate_servers")); bson_iter_bson (&iter, &candidates); /* read in eligible servers */ assert (bson_iter_init_find(&iter, test, "eligible_servers")); bson_iter_bson (&iter, &eligible); /* read in suitable servers */ assert (bson_iter_init_find(&iter, test, "suitable_servers")); bson_iter_bson (&iter, &suitable); /* read in latency window servers */ assert (bson_iter_init_find(&iter, test, "in_latency_window")); bson_iter_bson (&iter, &latency); _mongoc_array_init (&selected_servers, sizeof(mongoc_server_description_t*)); mongoc_topology_description_suitable_servers (&selected_servers, op, &topology, read_prefs, 15); bson_iter_init (&iter, &latency); assert (bson_count_keys(&latency) == selected_servers.len); while (bson_iter_next(&iter)) { bool found = false; bson_iter_t host; bson_iter_recurse(&iter, &host); bson_iter_find (&host, "address"); for (j = 0; j < selected_servers.len; j++) { sd = _mongoc_array_index (&selected_servers, mongoc_server_description_t*, j); if (strcmp(sd->host.host_and_port, bson_iter_utf8(&host, NULL)) == 0) { found = true; break; } } assert (found); } mongoc_read_prefs_destroy (read_prefs); mongoc_topology_description_destroy(&topology); _mongoc_array_destroy (&selected_servers); } /* *----------------------------------------------------------------------- * * Runner for the JSON tests for server selection. * *----------------------------------------------------------------------- */ static void test_all_spec_tests (TestSuite *suite) { char resolved[PATH_MAX]; /* RTT calculation */ if (realpath ("tests/json/server_selection/rtt", resolved)) { install_json_test_suite(suite, resolved, &test_rtt_calculation_cb); } /* SS logic */ if (realpath ("tests/json/server_selection/server_selection", resolved)) { install_json_test_suite(suite, resolved, &test_server_selection_logic_cb); } } void test_server_selection_install (TestSuite *suite) { test_all_spec_tests(suite); } libmongoc-1.3.1/tests/test-mongoc-set.c000066400000000000000000000032501264720626300200330ustar00rootroot00000000000000#include #include "mongoc-set-private.h" #include "TestSuite.h" static void test_set_dtor (void * item_, void * ctx_) { int *destroyed = (int *)ctx_; (*destroyed)++; } static bool test_set_visit_cb (void * item_, void * ctx_) { int *visited = (int *)ctx_; (*visited)++; return true; } static bool test_set_stop_after_cb (void * item_, void * ctx_) { int *stop_after = (int *)ctx_; (*stop_after)--; return *stop_after > 0; } static void test_set_new (void) { void * items[10]; int i; int destroyed = 0; int visited = 0; int stop_after = 3; mongoc_set_t * set = mongoc_set_new(2, &test_set_dtor, &destroyed); for (i = 0; i < 5; i++) { mongoc_set_add(set, i, items + i); } for (i = 0; i < 5; i++) { assert( mongoc_set_get(set, i) == items + i); } mongoc_set_rm(set, 0); assert (destroyed == 1); for (i = 5; i < 10; i++) { mongoc_set_add(set, i, items + i); } for (i = 5; i < 10; i++) { assert( mongoc_set_get(set, i) == items + i); } mongoc_set_rm(set, 9); assert (destroyed == 2); mongoc_set_rm(set, 5); assert (destroyed == 3); assert( mongoc_set_get(set, 1) == items + 1); assert( mongoc_set_get(set, 7) == items + 7); assert( ! mongoc_set_get(set, 5) ); mongoc_set_add(set, 5, items + 5); assert( mongoc_set_get(set, 5) == items + 5); mongoc_set_for_each(set, test_set_visit_cb, &visited); assert( visited == 8 ); mongoc_set_for_each(set, test_set_stop_after_cb, &stop_after); assert( stop_after == 0 ); mongoc_set_destroy(set); } void test_set_install (TestSuite *suite) { TestSuite_Add (suite, "/Set/new", test_set_new); } libmongoc-1.3.1/tests/test-mongoc-socket.c000066400000000000000000000234541264720626300205400ustar00rootroot00000000000000#include #include #include "mongoc-tests.h" #include "mongoc-socket-private.h" #include "mongoc-thread-private.h" #include "mongoc-errno-private.h" #include "TestSuite.h" #include "test-libmongoc.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "socket-test" #define TIMEOUT 10000 #define WAIT 1000 static size_t gFourMB = 1024 * 1024 * 4; typedef struct { unsigned short server_port; mongoc_cond_t cond; mongoc_mutex_t cond_mutex; bool closed_socket; int amount; } socket_test_data_t; static void * socket_test_server (void *data_) { socket_test_data_t *data = (socket_test_data_t *)data_; struct sockaddr_in server_addr = { 0 }; mongoc_socket_t *listen_sock; mongoc_socket_t *conn_sock; mongoc_stream_t *stream; mongoc_iovec_t iov; socklen_t sock_len; ssize_t r; char buf[5]; iov.iov_base = buf; iov.iov_len = sizeof (buf); listen_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (listen_sock); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); server_addr.sin_port = htons (0); r = mongoc_socket_bind (listen_sock, (struct sockaddr *)&server_addr, sizeof server_addr); assert (r == 0); sock_len = sizeof(server_addr); r = mongoc_socket_getsockname (listen_sock, (struct sockaddr *)&server_addr, &sock_len); assert(r == 0); r = mongoc_socket_listen (listen_sock, 10); assert(r == 0); mongoc_mutex_lock(&data->cond_mutex); data->server_port = ntohs(server_addr.sin_port); mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); conn_sock = mongoc_socket_accept (listen_sock, -1); assert (conn_sock); stream = mongoc_stream_socket_new (conn_sock); assert (stream); r = mongoc_stream_readv (stream, &iov, 1, 5, TIMEOUT); assert (r == 5); assert (strcmp (buf, "ping") == 0); strcpy (buf, "pong"); r = mongoc_stream_writev (stream, &iov, 1, TIMEOUT); assert (r == 5); mongoc_stream_destroy (stream); mongoc_mutex_lock(&data->cond_mutex); data->closed_socket = true; mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); mongoc_socket_destroy (listen_sock); return NULL; } static void * socket_test_client (void *data_) { socket_test_data_t *data = (socket_test_data_t *)data_; mongoc_socket_t *conn_sock; char buf[5]; ssize_t r; bool closed; struct sockaddr_in server_addr = { 0 }; mongoc_stream_t *stream; mongoc_iovec_t iov; iov.iov_base = buf; iov.iov_len = sizeof (buf); conn_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (conn_sock); mongoc_mutex_lock(&data->cond_mutex); while (! data->server_port) { mongoc_cond_wait(&data->cond, &data->cond_mutex); } mongoc_mutex_unlock(&data->cond_mutex); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(data->server_port); server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); r = mongoc_socket_connect (conn_sock, (struct sockaddr *)&server_addr, sizeof(server_addr), -1); assert (r == 0); stream = mongoc_stream_socket_new (conn_sock); strcpy (buf, "ping"); closed = mongoc_stream_check_closed (stream); assert (closed == false); r = mongoc_stream_writev (stream, &iov, 1, TIMEOUT); assert (r == 5); closed = mongoc_stream_check_closed (stream); assert (closed == false); r = mongoc_stream_readv (stream, &iov, 1, 5, TIMEOUT); assert (r == 5); assert (strcmp (buf, "pong") == 0); mongoc_mutex_lock(&data->cond_mutex); while (! data->closed_socket) { mongoc_cond_wait(&data->cond, &data->cond_mutex); } mongoc_mutex_unlock(&data->cond_mutex); closed = mongoc_stream_check_closed (stream); assert (closed == true); mongoc_stream_destroy (stream); return NULL; } static void * sendv_test_server (void *data_) { socket_test_data_t *data = (socket_test_data_t *)data_; struct sockaddr_in server_addr = { 0 }; mongoc_socket_t *listen_sock; mongoc_socket_t *conn_sock; mongoc_stream_t *stream; mongoc_iovec_t iov; socklen_t sock_len; int amount = 0; ssize_t r; char *buf = (char *)bson_malloc (gFourMB); iov.iov_base = buf; iov.iov_len = gFourMB; listen_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (listen_sock); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); server_addr.sin_port = htons (0); r = mongoc_socket_bind (listen_sock, (struct sockaddr *)&server_addr, sizeof server_addr); assert (r == 0); sock_len = sizeof(server_addr); r = mongoc_socket_getsockname (listen_sock, (struct sockaddr *)&server_addr, &sock_len); assert(r == 0); r = mongoc_socket_listen (listen_sock, 10); assert(r == 0); mongoc_mutex_lock(&data->cond_mutex); data->server_port = ntohs(server_addr.sin_port); mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); conn_sock = mongoc_socket_accept (listen_sock, -1); assert (conn_sock); stream = mongoc_stream_socket_new (conn_sock); assert (stream); /* Wait until the client has pushed so much data he can't write more */ mongoc_mutex_lock(&data->cond_mutex); while (! data->amount) { mongoc_cond_wait(&data->cond, &data->cond_mutex); } amount = data->amount; data->amount = 0; mongoc_mutex_unlock(&data->cond_mutex); /* Start reading everything off the socket to unblock the client */ do { r = mongoc_stream_readv (stream, &iov, 1, amount, WAIT); if (r > 0) { amount -= r; } else if (MONGOC_ERRNO_IS_AGAIN(errno)) { continue; } else { fprintf(stderr, "r: %"PRIu64" , errno: %d", (uint64_t)r, conn_sock->errno_); assert (r == amount); } } while (amount > 0); /* Allow the client to finish all its writes */ mongoc_mutex_lock(&data->cond_mutex); while (! data->amount) { mongoc_cond_wait(&data->cond, &data->cond_mutex); } /* amount is likely negative value now, we've read more then caused the original blocker */ amount += data->amount; data->amount = 0; mongoc_mutex_unlock(&data->cond_mutex); do { r = mongoc_stream_readv (stream, &iov, 1, amount, WAIT); if (r > 0) { amount -= r; } else if (MONGOC_ERRNO_IS_AGAIN(errno)) { continue; } else { fprintf(stderr, "r: %"PRIu64" , errno: %d", (uint64_t)r, errno); assert (r == amount); } } while (amount > 0); ASSERT_CMPINT(0, ==, amount); mongoc_stream_destroy (stream); mongoc_socket_destroy (listen_sock); return NULL; } static void * sendv_test_client (void *data_) { socket_test_data_t *data = (socket_test_data_t *)data_; mongoc_socket_t *conn_sock; ssize_t r; int i; int amount = 0; struct sockaddr_in server_addr = { 0 }; mongoc_stream_t *stream; mongoc_iovec_t iov; bool done = false; char *buf = (char *)bson_malloc (gFourMB); memset (buf, 'a', (gFourMB)- 1); buf[gFourMB - 1] = '\0'; iov.iov_base = buf; iov.iov_len = gFourMB; conn_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (conn_sock); mongoc_mutex_lock(&data->cond_mutex); while (! data->server_port) { mongoc_cond_wait(&data->cond, &data->cond_mutex); } mongoc_mutex_unlock(&data->cond_mutex); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(data->server_port); server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); r = mongoc_socket_connect (conn_sock, (struct sockaddr *)&server_addr, sizeof(server_addr), -1); assert (r == 0); stream = mongoc_stream_socket_new (conn_sock); for (i = 0; i < 5; i++) { r = mongoc_stream_writev (stream, &iov, 1, WAIT); if (r > 0) { amount += r; } if (r != gFourMB) { if (MONGOC_ERRNO_IS_AGAIN(conn_sock->errno_)) { if (!done) { mongoc_mutex_lock(&data->cond_mutex); data->amount = amount; amount = 0; mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); done = true; } } else { assert (r == gFourMB); } } } assert(true == done); mongoc_mutex_lock(&data->cond_mutex); data->amount = amount; mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); mongoc_stream_destroy (stream); return NULL; } static void test_mongoc_socket_check_closed (void) { socket_test_data_t data = { 0 }; mongoc_thread_t threads[2]; int i, r; mongoc_mutex_init (&data.cond_mutex); mongoc_cond_init (&data.cond); r = mongoc_thread_create (threads, &socket_test_server, &data); assert (r == 0); r = mongoc_thread_create (threads + 1, &socket_test_client, &data); assert (r == 0); for (i = 0; i < 2; i++) { r = mongoc_thread_join (threads[i]); assert (r == 0); } mongoc_mutex_destroy (&data.cond_mutex); mongoc_cond_destroy (&data.cond); } static void test_mongoc_socket_sendv (void) { socket_test_data_t data = { 0 }; mongoc_thread_t threads[2]; int i, r; mongoc_mutex_init (&data.cond_mutex); mongoc_cond_init (&data.cond); r = mongoc_thread_create (threads, &sendv_test_server, &data); assert (r == 0); r = mongoc_thread_create (threads + 1, &sendv_test_client, &data); assert (r == 0); for (i = 0; i < 2; i++) { r = mongoc_thread_join (threads[i]); assert (r == 0); } mongoc_mutex_destroy (&data.cond_mutex); mongoc_cond_destroy (&data.cond); } void test_socket_install (TestSuite *suite) { TestSuite_Add (suite, "/Socket/check_closed", test_mongoc_socket_check_closed); TestSuite_Add (suite, "/Socket/sendv", test_mongoc_socket_sendv); } libmongoc-1.3.1/tests/test-mongoc-stream-tls-error.c000066400000000000000000000214021264720626300224610ustar00rootroot00000000000000#include #include #include #include #include "ssl-test.h" #include "TestSuite.h" #define TIMEOUT 10000 /* milliseconds */ /** run as a child thread by test_mongoc_tls_hangup * * It: * 1. spins up * 2. binds and listens to a random port * 3. notifies the client of its port through a condvar * 4. accepts a request * 5. reads a byte * 7. hangs up */ static void * ssl_error_server (void *ptr) { ssl_test_data_t *data = (ssl_test_data_t *)ptr; mongoc_stream_t *sock_stream; mongoc_stream_t *ssl_stream; mongoc_socket_t *listen_sock; mongoc_socket_t *conn_sock; socklen_t sock_len; char buf; ssize_t r; mongoc_iovec_t iov; struct sockaddr_in server_addr = { 0 }; iov.iov_base = &buf; iov.iov_len = 1; listen_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (listen_sock); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); server_addr.sin_port = htons (0); r = mongoc_socket_bind (listen_sock, (struct sockaddr *)&server_addr, sizeof server_addr); assert (r == 0); sock_len = sizeof (server_addr); r = mongoc_socket_getsockname (listen_sock, (struct sockaddr *)&server_addr, &sock_len); assert (r == 0); r = mongoc_socket_listen (listen_sock, 10); assert (r == 0); mongoc_mutex_lock (&data->cond_mutex); data->server_port = ntohs (server_addr.sin_port); mongoc_cond_signal (&data->cond); mongoc_mutex_unlock (&data->cond_mutex); conn_sock = mongoc_socket_accept (listen_sock, -1); assert (conn_sock); sock_stream = mongoc_stream_socket_new (conn_sock); assert (sock_stream); ssl_stream = mongoc_stream_tls_new (sock_stream, data->server, 0); assert (ssl_stream); switch (data->behavior) { case SSL_TEST_BEHAVIOR_STALL_BEFORE_HANDSHAKE: _mongoc_usleep (data->handshake_stall_ms * 1000); break; case SSL_TEST_BEHAVIOR_HANGUP_AFTER_HANDSHAKE: r = mongoc_stream_tls_do_handshake (ssl_stream, TIMEOUT); assert (r); r = mongoc_stream_readv (ssl_stream, &iov, 1, 1, TIMEOUT); assert (r == 1); break; case SSL_TEST_BEHAVIOR_NORMAL: default: fprintf (stderr, "unimplemented ssl_test_behavior_t\n"); abort (); } data->server_result->result = SSL_TEST_SUCCESS; mongoc_stream_close (ssl_stream); mongoc_stream_destroy (ssl_stream); mongoc_socket_destroy (listen_sock); return NULL; } #define TRUST_DIR "tests/trust_dir" #define PEMFILE_NOPASS TRUST_DIR "/keys/mongodb.com.pem" #if !defined(__sun) /** run as a child thread by test_mongoc_tls_hangup * * It: * 1. spins up * 2. waits on a condvar until the server is up * 3. connects to the server's port * 4. writes a byte * 5. confirms that the server hangs up promptly * 6. shuts down */ static void * ssl_hangup_client (void *ptr) { ssl_test_data_t *data = (ssl_test_data_t *)ptr; mongoc_stream_t *sock_stream; mongoc_stream_t *ssl_stream; mongoc_socket_t *conn_sock; char buf = 'b'; ssize_t r; mongoc_iovec_t riov; mongoc_iovec_t wiov; struct sockaddr_in server_addr = { 0 }; int64_t start_time; conn_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (conn_sock); mongoc_mutex_lock (&data->cond_mutex); while (!data->server_port) { mongoc_cond_wait (&data->cond, &data->cond_mutex); } mongoc_mutex_unlock (&data->cond_mutex); server_addr.sin_family = AF_INET; server_addr.sin_port = htons (data->server_port); server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); r = mongoc_socket_connect (conn_sock, (struct sockaddr *)&server_addr, sizeof (server_addr), -1); assert (r == 0); sock_stream = mongoc_stream_socket_new (conn_sock); assert (sock_stream); ssl_stream = mongoc_stream_tls_new (sock_stream, data->client, 1); assert (ssl_stream); r = mongoc_stream_tls_do_handshake (ssl_stream, TIMEOUT); assert (r); wiov.iov_base = (void *)&buf; wiov.iov_len = 1; r = mongoc_stream_writev (ssl_stream, &wiov, 1, TIMEOUT); assert (r == 1); riov.iov_base = (void *)&buf; riov.iov_len = 1; /* we should notice promptly that the server hangs up */ start_time = bson_get_monotonic_time (); r = mongoc_stream_readv (ssl_stream, &riov, 1, 1, TIMEOUT); /* time is in microseconds */ assert (bson_get_monotonic_time () - start_time < 1000 * 1000); assert (r == -1); mongoc_stream_destroy (ssl_stream); data->client_result->result = SSL_TEST_SUCCESS; return NULL; } static void test_mongoc_tls_hangup (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; ssl_test_data_t data = { 0 }; mongoc_thread_t threads[2]; int i, r; sopt.pem_file = PEMFILE_NOPASS; sopt.weak_cert_validation = 1; copt.weak_cert_validation = 1; data.server = &sopt; data.client = &copt; data.behavior = SSL_TEST_BEHAVIOR_HANGUP_AFTER_HANDSHAKE; data.server_result = &sr; data.client_result = &cr; data.host = "localhost"; mongoc_mutex_init (&data.cond_mutex); mongoc_cond_init (&data.cond); r = mongoc_thread_create (threads, &ssl_error_server, &data); assert (r == 0); r = mongoc_thread_create (threads + 1, &ssl_hangup_client, &data); assert (r == 0); for (i = 0; i < 2; i++) { r = mongoc_thread_join (threads[i]); assert (r == 0); } mongoc_mutex_destroy (&data.cond_mutex); mongoc_cond_destroy (&data.cond); ASSERT (cr.result == SSL_TEST_SUCCESS); ASSERT (sr.result == SSL_TEST_SUCCESS); } #endif /** run as a child thread by test_mongoc_tls_handshake_stall * * It: * 1. spins up * 2. waits on a condvar until the server is up * 3. connects to the server's port * 4. attempts handshake * 5. confirms that it times out * 6. shuts down */ static void * handshake_stall_client (void *ptr) { ssl_test_data_t *data = (ssl_test_data_t *)ptr; char *uri_str; mongoc_client_t *client; bson_t reply; bson_error_t error; int64_t connect_timeout_ms = data->handshake_stall_ms - 100; int64_t duration_ms; int64_t start_time; mongoc_mutex_lock (&data->cond_mutex); while (!data->server_port) { mongoc_cond_wait (&data->cond, &data->cond_mutex); } mongoc_mutex_unlock (&data->cond_mutex); uri_str = bson_strdup_printf ( "mongodb://localhost:%u/?ssl=true&serverselectiontimeoutms=200&connecttimeoutms=%" PRId64, data->server_port, connect_timeout_ms); client = mongoc_client_new (uri_str); /* we should time out after about 200ms */ start_time = bson_get_monotonic_time (); mongoc_client_get_server_status (client, NULL, &reply, &error); /* time is in microseconds */ duration_ms = (bson_get_monotonic_time () - start_time) / 1000; if (llabs(duration_ms - connect_timeout_ms) > 100) { fprintf (stderr, "expected timeout after about 200ms, not %" PRId64 "\n", duration_ms); abort (); } data->client_result->result = SSL_TEST_SUCCESS; bson_destroy (&reply); mongoc_client_destroy (client); bson_free (uri_str); return NULL; } static void test_mongoc_tls_handshake_stall (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; ssl_test_data_t data = { 0 }; mongoc_thread_t threads[2]; int i, r; sopt.pem_file = PEMFILE_NOPASS; sopt.weak_cert_validation = 1; copt.weak_cert_validation = 1; data.server = &sopt; data.client = &copt; data.behavior = SSL_TEST_BEHAVIOR_STALL_BEFORE_HANDSHAKE; data.handshake_stall_ms = 300; data.server_result = &sr; data.client_result = &cr; data.host = "localhost"; mongoc_mutex_init (&data.cond_mutex); mongoc_cond_init (&data.cond); r = mongoc_thread_create (threads, &ssl_error_server, &data); assert (r == 0); r = mongoc_thread_create (threads + 1, &handshake_stall_client, &data); assert (r == 0); for (i = 0; i < 2; i++) { r = mongoc_thread_join (threads[i]); assert (r == 0); } mongoc_mutex_destroy (&data.cond_mutex); mongoc_cond_destroy (&data.cond); ASSERT (cr.result == SSL_TEST_SUCCESS); ASSERT (sr.result == SSL_TEST_SUCCESS); } void test_stream_tls_error_install (TestSuite *suite) { /* TLS stream doesn't detect hangup promptly on Solaris for some reason */ #if !defined(__sun) TestSuite_Add (suite, "/TLS/hangup", test_mongoc_tls_hangup); #endif TestSuite_Add (suite, "/TLS/handshake_stall", test_mongoc_tls_handshake_stall); } libmongoc-1.3.1/tests/test-mongoc-stream-tls.c000066400000000000000000000133621264720626300213400ustar00rootroot00000000000000#include #include #include "ssl-test.h" #include "TestSuite.h" #define HOST "mongodb.com" #define TRUST_DIR "tests/trust_dir" #define VERIFY_DIR TRUST_DIR "/verify" #define CRLFILE TRUST_DIR "/crl/root.crl.pem" #define CAFILE TRUST_DIR "/verify/mongo_root.pem" #define PEMFILE_PASS TRUST_DIR "/keys/pass.mongodb.com.pem" #define PEMFILE_ALT TRUST_DIR "/keys/alt.mongodb.com.pem" #define PEMFILE_LOCALHOST TRUST_DIR "/keys/127.0.0.1.pem" #define PEMFILE_NOPASS TRUST_DIR "/keys/mongodb.com.pem" #define PEMFILE_REV TRUST_DIR "/keys/rev.mongodb.com.pem" #define PASSWORD "testpass" static void test_mongoc_tls_no_certs (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; ssl_test (&copt, &sopt, "doesnt_matter", &cr, &sr); ASSERT (cr.result == SSL_TEST_SSL_HANDSHAKE); ASSERT (sr.result == SSL_TEST_SSL_HANDSHAKE); } static void test_mongoc_tls_password (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_PASS; sopt.ca_file = CAFILE; sopt.pem_pwd = PASSWORD; copt.ca_file = CAFILE; ssl_test (&copt, &sopt, "pass.mongodb.com", &cr, &sr); ASSERT (cr.result == SSL_TEST_SUCCESS); ASSERT (sr.result == SSL_TEST_SUCCESS); } static void test_mongoc_tls_bad_password (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_PASS; sopt.ca_file = CAFILE; sopt.pem_pwd = "badpass"; copt.ca_file = CAFILE; ssl_test (&copt, &sopt, "pass.mongodb.com", &cr, &sr); ASSERT (cr.result == SSL_TEST_SSL_HANDSHAKE); ASSERT (sr.result == SSL_TEST_SSL_INIT); } static void test_mongoc_tls_no_verify (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_NOPASS; sopt.ca_file = CAFILE; copt.ca_file = CAFILE; copt.weak_cert_validation = 1; ssl_test (&copt, &sopt, "bad_domain.com", &cr, &sr); ASSERT (cr.result == SSL_TEST_SUCCESS); ASSERT (sr.result == SSL_TEST_SUCCESS); } static void test_mongoc_tls_bad_verify (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_NOPASS; sopt.ca_file = CAFILE; copt.ca_file = CAFILE; ssl_test (&copt, &sopt, "bad_domain.com", &cr, &sr); ASSERT (cr.result == SSL_TEST_SSL_VERIFY); ASSERT (sr.result == SSL_TEST_TIMEOUT); } static void test_mongoc_tls_basic (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_NOPASS; sopt.ca_file = CAFILE; copt.ca_file = CAFILE; ssl_test (&copt, &sopt, HOST, &cr, &sr); ASSERT (cr.result == SSL_TEST_SUCCESS); ASSERT (sr.result == SSL_TEST_SUCCESS); } static void test_mongoc_tls_crl (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_REV; sopt.ca_file = CAFILE; copt.ca_file = CAFILE; copt.crl_file = CRLFILE; ssl_test (&copt, &sopt, "rev.mongodb.com", &cr, &sr); ASSERT (cr.result == SSL_TEST_SSL_VERIFY); ASSERT (sr.result == SSL_TEST_TIMEOUT); } static void test_mongoc_tls_altname (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_ALT; sopt.ca_file = CAFILE; copt.ca_file = CAFILE; ssl_test (&copt, &sopt, "alt2.mongodb.com", &cr, &sr); ASSERT (cr.result == SSL_TEST_SUCCESS); ASSERT (sr.result == SSL_TEST_SUCCESS); } static void test_mongoc_tls_wild (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_ALT; sopt.ca_file = CAFILE; copt.ca_file = CAFILE; ssl_test (&copt, &sopt, "unicorn.wild.mongodb.com", &cr, &sr); ASSERT (cr.result == SSL_TEST_SUCCESS); ASSERT (sr.result == SSL_TEST_SUCCESS); } static void test_mongoc_tls_ip (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_ALT; sopt.ca_file = CAFILE; copt.ca_file = CAFILE; ssl_test (&copt, &sopt, "10.0.0.1", &cr, &sr); ASSERT (cr.result == SSL_TEST_SUCCESS); ASSERT (sr.result == SSL_TEST_SUCCESS); } #ifndef _WIN32 static void test_mongoc_tls_trust_dir (void) { mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; ssl_test_result_t sr; ssl_test_result_t cr; sopt.pem_file = PEMFILE_NOPASS; sopt.ca_dir = VERIFY_DIR; copt.ca_dir = VERIFY_DIR; ssl_test (&copt, &sopt, HOST, &cr, &sr); ASSERT (cr.result == SSL_TEST_SUCCESS); ASSERT (sr.result == SSL_TEST_SUCCESS); } #endif void test_stream_tls_install (TestSuite *suite) { TestSuite_Add (suite, "/TLS/altname", test_mongoc_tls_altname); TestSuite_Add (suite, "/TLS/bad_password", test_mongoc_tls_bad_password); TestSuite_Add (suite, "/TLS/bad_verify", test_mongoc_tls_bad_verify); TestSuite_Add (suite, "/TLS/basic", test_mongoc_tls_basic); TestSuite_Add (suite, "/TLS/crl", test_mongoc_tls_crl); TestSuite_Add (suite, "/TLS/ip", test_mongoc_tls_ip); TestSuite_Add (suite, "/TLS/no_certs", test_mongoc_tls_no_certs); TestSuite_Add (suite, "/TLS/no_verify", test_mongoc_tls_no_verify); TestSuite_Add (suite, "/TLS/password", test_mongoc_tls_password); #ifndef _WIN32 TestSuite_Add (suite, "/TLS/trust_dir", test_mongoc_tls_trust_dir); #endif TestSuite_Add (suite, "/TLS/wild", test_mongoc_tls_wild); } libmongoc-1.3.1/tests/test-mongoc-stream.c000066400000000000000000000103101264720626300205260ustar00rootroot00000000000000#include "mongoc-tests.h" #include #include #include #include #include "TestSuite.h" static void test_buffered_basic (void) { mongoc_stream_t *stream; mongoc_stream_t *buffered; mongoc_iovec_t iov; ssize_t r; char buf[16236]; stream = mongoc_stream_file_new_for_path (BINARY_DIR"/reply2.dat", O_RDONLY, 0); assert (stream); /* buffered assumes ownership of stream */ buffered = mongoc_stream_buffered_new(stream, 1024); /* try to read large chunk larger than buffer. */ iov.iov_len = sizeof buf; iov.iov_base = buf; r = mongoc_stream_readv(buffered, &iov, 1, iov.iov_len, -1); if (r != iov.iov_len) { char msg[100]; bson_snprintf(msg, 100, "Expected %lld got %llu", (long long)r, (unsigned long long)iov.iov_len); ASSERT_CMPSTR(msg, "failed"); } /* cleanup */ mongoc_stream_destroy(buffered); } static void test_buffered_oversized (void) { mongoc_stream_t *stream; mongoc_stream_t *buffered; mongoc_iovec_t iov; ssize_t r; char buf[16236]; stream = mongoc_stream_file_new_for_path (BINARY_DIR"/reply2.dat", O_RDONLY, 0); assert (stream); /* buffered assumes ownership of stream */ buffered = mongoc_stream_buffered_new(stream, 20000); /* try to read large chunk larger than buffer. */ iov.iov_len = sizeof buf; iov.iov_base = buf; r = mongoc_stream_readv(buffered, &iov, 1, iov.iov_len, -1); if (r != iov.iov_len) { char msg[100]; bson_snprintf(msg, 100, "Expected %lld got %llu", (long long)r, (unsigned long long)iov.iov_len); ASSERT_CMPSTR(msg, "failed"); } /* cleanup */ mongoc_stream_destroy(buffered); } typedef struct { mongoc_stream_t vtable; ssize_t rval; } failing_stream_t; static ssize_t failing_stream_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { failing_stream_t *fstream = (failing_stream_t *)stream; return fstream->rval; } void failing_stream_destroy (mongoc_stream_t *stream) { bson_free (stream); } static mongoc_stream_t * failing_stream_new (ssize_t rval) { failing_stream_t *stream; stream = bson_malloc0 (sizeof *stream); stream->vtable.type = 999; stream->vtable.writev = failing_stream_writev; stream->vtable.destroy = failing_stream_destroy; stream->rval = rval; return (mongoc_stream_t *)stream; } static void test_stream_writev_full (void) { mongoc_stream_t *error_stream = failing_stream_new (-1); mongoc_stream_t *short_stream = failing_stream_new (10); mongoc_stream_t *success_stream = failing_stream_new (100); char bufa[20]; char bufb[80]; bool r; mongoc_iovec_t iov[2]; bson_error_t error = { 0 }; const char *error_message = "Failure during socket delivery: "; const char *short_message = "Failure to send all requested bytes (only sent: 10/100 in 100ms) during socket delivery"; iov[0].iov_base = bufa; iov[0].iov_len = sizeof (bufa); iov[1].iov_base = bufb; iov[1].iov_len = sizeof (bufb); errno = EINVAL; r = _mongoc_stream_writev_full (error_stream, iov, 2, 100, &error); BSON_ASSERT (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_STREAM); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_STREAM_SOCKET); ASSERT_STARTSWITH (error.message, error_message); errno = 0; r = _mongoc_stream_writev_full (short_stream, iov, 2, 100, &error); BSON_ASSERT (!r); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_STREAM); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_STREAM_SOCKET); ASSERT_CMPSTR (error.message, short_message); errno = 0; r = _mongoc_stream_writev_full (success_stream, iov, 2, 100, &error); BSON_ASSERT (r); mongoc_stream_destroy (error_stream); mongoc_stream_destroy (short_stream); mongoc_stream_destroy (success_stream); } void test_stream_install (TestSuite *suite) { TestSuite_Add (suite, "/Stream/buffered/basic", test_buffered_basic); TestSuite_Add (suite, "/Stream/buffered/oversized", test_buffered_oversized); TestSuite_Add (suite, "/Stream/writev_full", test_stream_writev_full); } libmongoc-1.3.1/tests/test-mongoc-thread.c000066400000000000000000000014501264720626300205070ustar00rootroot00000000000000#include "mongoc-thread-private.h" #include "TestSuite.h" static void test_cond_wait (void) { int64_t start, duration_usec; mongoc_mutex_t mutex; mongoc_cond_t cond; mongoc_mutex_init (&mutex); mongoc_cond_init (&cond); mongoc_mutex_lock (&mutex); start = bson_get_monotonic_time (); mongoc_cond_timedwait (&cond, &mutex, 100); duration_usec = bson_get_monotonic_time () - start; mongoc_mutex_unlock (&mutex); if (!((50 * 1000 < duration_usec) && (150 * 1000 > duration_usec))) { fprintf (stderr, "expected to wait 100ms, waited %" PRId64 "\n", duration_usec); } mongoc_cond_destroy (&cond); mongoc_mutex_destroy (&mutex); } void test_thread_install (TestSuite *suite) { TestSuite_Add (suite, "/Thread/cond_wait", test_cond_wait); } libmongoc-1.3.1/tests/test-mongoc-topology-reconcile.c000066400000000000000000000230621264720626300230600ustar00rootroot00000000000000#include #include "mongoc-client-private.h" #include "utlist.h" #include "mock_server/future.h" #include "mock_server/future-functions.h" #include "mock_server/mock-server.h" #include "TestSuite.h" #include "test-conveniences.h" #include "test-libmongoc.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "topology-reconcile-test" static const mongoc_topology_scanner_node_t * get_node (mongoc_topology_t *topology, const char *host_and_port) { const mongoc_topology_scanner_t *ts; const mongoc_topology_scanner_node_t *node; const mongoc_topology_scanner_node_t *sought = NULL; mongoc_mutex_lock (&topology->mutex); ts = topology->scanner; DL_FOREACH (ts->nodes, node) { if (!strcmp (host_and_port, node->host.host_and_port)) { sought = node; break; } } mongoc_mutex_unlock (&topology->mutex); return sought; } void rs_response_to_ismaster (mock_server_t *server, bool primary, bool has_tags, ...) { va_list ap; bson_string_t *hosts; bool first; mock_server_t *host; char *ismaster_response; hosts = bson_string_new (""); va_start (ap, has_tags); first = true; while ((host = va_arg (ap, mock_server_t *))) { if (first) { first = false; } else { bson_string_append (hosts, ","); } bson_string_append_printf (hosts, "'%s'", mock_server_get_host_and_port (host)); } va_end (ap); ismaster_response = bson_strdup_printf ( "{'ok': 1, " " 'setName': 'rs'," " 'ismaster': %s," " 'secondary': %s," " 'tags': {%s}," " 'hosts': [%s]" "}", primary ? "true" : "false", primary ? "false" : "true", has_tags ? "'key': 'value'" : "", hosts->str); mock_server_auto_ismaster (server, ismaster_response); bson_free (ismaster_response); bson_string_free (hosts, true); } #define RS_RESPONSE_TO_ISMASTER(server, primary, has_tags, ...) \ rs_response_to_ismaster (server, primary, has_tags, __VA_ARGS__, NULL) bool selects_server (mongoc_client_t *client, mongoc_read_prefs_t *read_prefs, mock_server_t *server) { bson_error_t error; mongoc_server_description_t *sd; bool result; sd = mongoc_topology_select (client->topology, MONGOC_SS_READ, read_prefs, 15, &error); if (!sd) { fprintf (stderr, "%s\n", error.message); return false; } result = (0 == strcmp (mongoc_server_description_host (sd)->host_and_port, mock_server_get_host_and_port (server))); mongoc_server_description_destroy (sd); return result; } static void _test_topology_reconcile_rs (bool pooled) { mock_server_t *server0; mock_server_t *server1; char *uri_str; mongoc_uri_t *uri; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; debug_stream_stats_t debug_stream_stats = { 0 }; mongoc_read_prefs_t *secondary_read_prefs; mongoc_read_prefs_t *primary_read_prefs; mongoc_read_prefs_t *tag_read_prefs; server0 = mock_server_new (); server1 = mock_server_new (); mock_server_run (server0); mock_server_run (server1); /* secondary, no tags */ RS_RESPONSE_TO_ISMASTER (server0, false, false, server0, server1); /* primary, no tags */ RS_RESPONSE_TO_ISMASTER (server1, true, false, server0, server1); /* provide secondary in seed list */ uri_str = bson_strdup_printf ( "mongodb://%s/?replicaSet=rs", mock_server_get_host_and_port (server0)); uri = mongoc_uri_new (uri_str); if (pooled) { pool = mongoc_client_pool_new (uri); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new (uri_str); } if (!pooled) { test_framework_set_debug_stream (client, &debug_stream_stats); } secondary_read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); primary_read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); tag_read_prefs = mongoc_read_prefs_new (MONGOC_READ_NEAREST); mongoc_read_prefs_add_tag (tag_read_prefs, tmp_bson ("{'key': 'value'}")); /* * server0 is selected, server1 is discovered and added to scanner. */ assert (selects_server (client, secondary_read_prefs, server0)); assert (get_node (client->topology, mock_server_get_host_and_port (server1))); /* * select again with mode "primary": server1 is selected. */ assert (selects_server (client, primary_read_prefs, server1)); /* * remove server1 from set. server0 is the primary, with tags. */ RS_RESPONSE_TO_ISMASTER (server0, true, true, server0); /* server1 absent */ assert (selects_server (client, tag_read_prefs, server0)); assert (!client->topology->stale); if (!pooled) { ASSERT_CMPINT (1, ==, debug_stream_stats.n_failed); } /* * server1 returns as a secondary. its scanner node is un-retired. */ RS_RESPONSE_TO_ISMASTER (server0, true, true, server0, server1); RS_RESPONSE_TO_ISMASTER (server1, false, false, server0, server1); assert (selects_server (client, secondary_read_prefs, server1)); if (!pooled) { /* no additional failed streams */ ASSERT_CMPINT (1, ==, debug_stream_stats.n_failed); } mongoc_read_prefs_destroy (primary_read_prefs); mongoc_read_prefs_destroy (secondary_read_prefs); mongoc_read_prefs_destroy (tag_read_prefs); if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } mongoc_uri_destroy (uri); bson_free (uri_str); mock_server_destroy (server1); mock_server_destroy (server0); } static void test_topology_reconcile_rs_single (void) { _test_topology_reconcile_rs (false); } static void test_topology_reconcile_rs_pooled (void) { _test_topology_reconcile_rs (true); } static void _test_topology_reconcile_sharded (bool pooled) { mock_server_t *mongos; mock_server_t *secondary; char *uri_str; mongoc_uri_t *uri; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; mongoc_read_prefs_t *primary_read_prefs; bson_error_t error; future_t *future; request_t *request; char *secondary_response; mongoc_server_description_t *sd; mongos = mock_server_new (); secondary = mock_server_new (); mock_server_run (mongos); mock_server_run (secondary); /* provide both servers in seed list */ uri_str = bson_strdup_printf ( "mongodb://%s,%s", mock_server_get_host_and_port (mongos), mock_server_get_host_and_port (secondary)); uri = mongoc_uri_new (uri_str); if (pooled) { pool = mongoc_client_pool_new (uri); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new (uri_str); } primary_read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); future = future_topology_select (client->topology, MONGOC_SS_READ, primary_read_prefs, 15, &error); /* mongos */ request = mock_server_receives_ismaster (mongos); mock_server_replies_simple ( request, "{'ok': 1, 'ismaster': true, 'msg': 'isdbgrid'}"); request_destroy (request); /* replica set secondary - topology removes it */ request = mock_server_receives_ismaster (secondary); secondary_response = bson_strdup_printf ( "{'ok': 1, " " 'setName': 'rs'," " 'ismaster': false," " 'secondary': true," " 'hosts': ['%s', '%s']" "}", mock_server_get_host_and_port (mongos), mock_server_get_host_and_port (secondary)); mock_server_replies_simple (request, secondary_response); request_destroy (request); /* * mongos is selected, secondary is removed. */ sd = future_get_mongoc_server_description_ptr (future); ASSERT_CMPSTR (sd->host.host_and_port, mock_server_get_host_and_port (mongos)); if (pooled) { /* wait a second for scanner thread to remove secondary */ int64_t start = bson_get_monotonic_time (); while (get_node (client->topology, mock_server_get_host_and_port (secondary))) { assert (bson_get_monotonic_time () - start < 1000000); } } else { assert (!get_node (client->topology, mock_server_get_host_and_port (secondary))); } mongoc_server_description_destroy (sd); bson_free (secondary_response); mongoc_read_prefs_destroy (primary_read_prefs); if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } future_destroy (future); mongoc_uri_destroy (uri); bson_free (uri_str); mock_server_destroy (secondary); mock_server_destroy (mongos); } static void test_topology_reconcile_sharded_single (void) { _test_topology_reconcile_sharded (false); } static void test_topology_reconcile_sharded_pooled (void) { _test_topology_reconcile_sharded (true); } void test_topology_reconcile_install (TestSuite *suite) { TestSuite_Add (suite, "/TOPOLOGY/reconcile/rs/pooled", test_topology_reconcile_rs_pooled); TestSuite_Add (suite, "/TOPOLOGY/reconcile/rs/single", test_topology_reconcile_rs_single); TestSuite_Add (suite, "/TOPOLOGY/reconcile/sharded/pooled", test_topology_reconcile_sharded_pooled); TestSuite_Add (suite, "/TOPOLOGY/reconcile/sharded/single", test_topology_reconcile_sharded_single); } libmongoc-1.3.1/tests/test-mongoc-topology-scanner.c000066400000000000000000000211631264720626300225460ustar00rootroot00000000000000#include #include "mongoc-util-private.h" #include "mongoc-client-private.h" #include "mongoc-tests.h" #include "TestSuite.h" #include "mock_server/mock-server.h" #include "mock_server/future.h" #include "mock_server/future-functions.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "topology-scanner-test" #define TIMEOUT 20000 /* milliseconds */ #define NSERVERS 10 #define TRUST_DIR "tests/trust_dir" #define CAFILE TRUST_DIR "/verify/mongo_root.pem" #define PEMFILE_NOPASS TRUST_DIR "/keys/mongodb.com.pem" static void test_topology_scanner_helper (uint32_t id, const bson_t *bson, int64_t rtt_msec, void *data, bson_error_t *error) { bson_iter_t iter; int *finished = (int*)data; uint32_t max_wire_version; if (error->code) { fprintf (stderr, "scanner error: %s\n", error->message); abort (); } /* mock servers are configured to return their ids as max wire version */ assert (bson); assert (bson_iter_init_find (&iter, bson, "maxWireVersion")); assert (BSON_ITER_HOLDS_INT32 (&iter)); max_wire_version = (uint32_t) bson_iter_int32 (&iter); ASSERT_CMPINT (max_wire_version, ==, id); (*finished)--; } static void _test_topology_scanner(bool with_ssl) { mock_server_t *servers[NSERVERS]; mongoc_topology_scanner_t *topology_scanner; int i; bson_t q = BSON_INITIALIZER; int finished = NSERVERS * 3; bool more_to_do; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t sopt = { 0 }; mongoc_ssl_opt_t copt = { 0 }; #endif topology_scanner = mongoc_topology_scanner_new ( NULL, &test_topology_scanner_helper, &finished); #ifdef MONGOC_ENABLE_SSL if (with_ssl) { copt.ca_file = CAFILE; copt.weak_cert_validation = 1; mongoc_topology_scanner_set_ssl_opts (topology_scanner, &copt); } #endif for (i = 0; i < NSERVERS; i++) { /* use max wire versions just to distinguish among responses */ servers[i] = mock_server_with_autoismaster (i); mock_server_set_rand_delay (servers[i], true); #ifdef MONGOC_ENABLE_SSL if (with_ssl) { sopt.pem_file = PEMFILE_NOPASS; sopt.ca_file = CAFILE; mock_server_set_ssl_opts (servers[i], &sopt); } #endif mock_server_run (servers[i]); mongoc_topology_scanner_add( topology_scanner, mongoc_uri_get_hosts (mock_server_get_uri (servers[i])), (uint32_t) i); } for (i = 0; i < 3; i++) { mongoc_topology_scanner_start (topology_scanner, TIMEOUT, false); more_to_do = mongoc_topology_scanner_work (topology_scanner, TIMEOUT); assert(! more_to_do); mongoc_topology_scanner_reset (topology_scanner); } assert(finished == 0); mongoc_topology_scanner_destroy (topology_scanner); bson_destroy (&q); for (i = 0; i < NSERVERS; i++) { mock_server_destroy (servers[i]); } } void test_topology_scanner () { _test_topology_scanner (false); } #ifdef MONGOC_ENABLE_SSL void test_topology_scanner_ssl () { _test_topology_scanner (true); } #endif /* * Servers discovered by a scan should be checked during that scan, CDRIVER-751. */ void test_topology_scanner_discovery () { mock_server_t *primary; mock_server_t *secondary; char *primary_response; char *secondary_response; mongoc_client_t *client; mongoc_topology_scanner_t *scanner; char *uri_str; mongoc_read_prefs_t *secondary_pref; bson_error_t error; future_t *future; request_t *request; mongoc_server_description_t *sd; primary = mock_server_new (); secondary = mock_server_new (); mock_server_run (primary); mock_server_run (secondary); primary_response = bson_strdup_printf ( "{'ok': 1, " " 'ismaster': true," " 'setName': 'rs'," " 'hosts': ['%s', '%s']}", mock_server_get_host_and_port (primary), mock_server_get_host_and_port (secondary)); secondary_response = bson_strdup_printf ( "{'ok': 1, " " 'ismaster': false," " 'secondary': true," " 'setName': 'rs'," " 'hosts': ['%s', '%s']}", mock_server_get_host_and_port (primary), mock_server_get_host_and_port (secondary)); uri_str = bson_strdup_printf ("mongodb://%s/?replicaSet=rs", mock_server_get_host_and_port (primary)); client = mongoc_client_new (uri_str); scanner = client->topology->scanner; secondary_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY_PREFERRED); future = future_topology_select (client->topology, MONGOC_SS_READ, secondary_pref, 15, &error); /* a single scan discovers *and* checks the secondary */ AWAIT (scanner->async->ncmds == 1); request = mock_server_receives_ismaster (primary); mock_server_replies_simple (request, primary_response); request_destroy (request); /* let client process that response */ _mongoc_usleep (250 * 1000); /* a check of the secondary is scheduled in this scan */ AWAIT (scanner->async->ncmds == 1); request = mock_server_receives_ismaster (secondary); mock_server_replies_simple (request, secondary_response); /* scan completes */ AWAIT (scanner->async->ncmds == 0); ASSERT_OR_PRINT ((sd = future_get_mongoc_server_description_ptr (future)), error); ASSERT_CMPSTR (sd->host.host_and_port, mock_server_get_host_and_port (secondary)); mongoc_server_description_destroy (sd); future_destroy (future); request_destroy (request); mongoc_read_prefs_destroy (secondary_pref); bson_free (secondary_response); bson_free (primary_response); bson_free (uri_str); mongoc_client_destroy (client); mock_server_destroy (secondary); mock_server_destroy (primary); } /* scanner shouldn't spin if two primaries point at each other */ void test_topology_scanner_oscillate () { mock_server_t *server0; mock_server_t *server1; char *server0_response; char *server1_response; mongoc_client_t *client; mongoc_topology_scanner_t *scanner; char *uri_str; mongoc_read_prefs_t *primary_pref; bson_error_t error; future_t *future; request_t *request; server0 = mock_server_new (); server1 = mock_server_new (); mock_server_run (server0); mock_server_run (server1); /* server 0 says it's primary, but only server 1 is in the set */ server0_response = bson_strdup_printf ( "{'ok': 1, " " 'ismaster': true," " 'setName': 'rs'," " 'hosts': ['%s']}", mock_server_get_host_and_port (server1)); /* the opposite */ server1_response = bson_strdup_printf ( "{'ok': 1, " " 'ismaster': true," " 'setName': 'rs'," " 'hosts': ['%s']}", mock_server_get_host_and_port (server0)); /* start with server 0 */ uri_str = bson_strdup_printf ("mongodb://%s/?replicaSet=rs", mock_server_get_host_and_port (server0)); client = mongoc_client_new (uri_str); scanner = client->topology->scanner; primary_pref = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); assert (!scanner->async->ncmds); future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); /* a single scan discovers servers 0 and 1 */ request = mock_server_receives_ismaster (server0); mock_server_replies_simple (request, server0_response); request_destroy (request); /* let client process that response */ _mongoc_usleep (250 * 1000); AWAIT (scanner->async->ncmds == 1); request = mock_server_receives_ismaster (server1); mock_server_replies_simple (request, server1_response); /* we don't schedule another check of server0 */ _mongoc_usleep (250 * 1000); AWAIT (scanner->async->ncmds == 0); assert (!future_get_mongoc_server_description_ptr (future)); assert (scanner->async->ncmds == 0); future_destroy (future); request_destroy (request); mongoc_read_prefs_destroy (primary_pref); bson_free (server1_response); bson_free (server0_response); bson_free (uri_str); mongoc_client_destroy (client); mock_server_destroy (server1); mock_server_destroy (server0); } void test_topology_scanner_install (TestSuite *suite) { TestSuite_Add (suite, "/TOPOLOGY/scanner", test_topology_scanner); #ifdef MONGOC_ENABLE_SSL TestSuite_Add (suite, "/TOPOLOGY/scanner_ssl", test_topology_scanner_ssl); #endif TestSuite_Add (suite, "/TOPOLOGY/scanner_discovery", test_topology_scanner_discovery); TestSuite_Add (suite, "/TOPOLOGY/scanner_oscillate", test_topology_scanner_oscillate); } libmongoc-1.3.1/tests/test-mongoc-topology.c000066400000000000000000000661701264720626300211260ustar00rootroot00000000000000#include #include #include "mongoc-client-private.h" #include "mongoc-tests.h" #include "mongoc-util-private.h" #include "TestSuite.h" #include "test-libmongoc.h" #include "mock_server/mock-server.h" #include "mock_server/future.h" #include "mock_server/future-functions.h" #include "test-conveniences.h" #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "topology-test" static void test_topology_client_creation (void) { mongoc_uri_t *uri; mongoc_topology_scanner_node_t *node; mongoc_topology_t *topology_a; mongoc_topology_t *topology_b; mongoc_client_t *client_a; mongoc_client_t *client_b; mongoc_stream_t *topology_stream; mongoc_server_stream_t *server_stream; bson_error_t error; uri = test_framework_get_uri (); mongoc_uri_set_option_as_int32 (uri, "connectTimeoutMS", 12345); mongoc_uri_set_option_as_int32 (uri, "serverSelectionTimeoutMS", 54321); /* create two clients directly */ client_a = mongoc_client_new_from_uri (uri); client_b = mongoc_client_new_from_uri (uri); assert (client_a); assert (client_b); test_framework_set_ssl_opts (client_a); test_framework_set_ssl_opts (client_b); /* ensure that they are using different topologies */ topology_a = client_a->topology; topology_b = client_b->topology; assert (topology_a); assert (topology_b); assert (topology_a != topology_b); assert (topology_a->connect_timeout_msec == 12345); assert (topology_a->server_selection_timeout_msec == 54321); /* ensure that their topologies are running in single-threaded mode */ assert (topology_a->single_threaded); assert (topology_a->bg_thread_state == MONGOC_TOPOLOGY_BG_OFF); /* ensure that we are sharing streams with the client */ server_stream = mongoc_cluster_stream_for_reads (&client_a->cluster, NULL, &error); ASSERT_OR_PRINT (server_stream, error); node = mongoc_topology_scanner_get_node (client_a->topology->scanner, server_stream->sd->id); assert (node); topology_stream = node->stream; assert (topology_stream); assert (topology_stream == server_stream->stream); mongoc_server_stream_cleanup (server_stream); mongoc_client_destroy (client_a); mongoc_client_destroy (client_b); mongoc_uri_destroy (uri); } static void test_topology_client_pool_creation (void) { mongoc_client_pool_t *pool; mongoc_client_t *client_a; mongoc_client_t *client_b; mongoc_topology_t *topology_a; mongoc_topology_t *topology_b; /* create two clients through a client pool */ pool = test_framework_client_pool_new (); client_a = mongoc_client_pool_pop (pool); client_b = mongoc_client_pool_pop (pool); assert (client_a); assert (client_b); /* ensure that they are using the same topology */ topology_a = client_a->topology; topology_b = client_b->topology; assert (topology_a); assert (topology_a == topology_b); /* ensure that that topology is running in a background thread */ assert (!topology_a->single_threaded); assert (topology_a->bg_thread_state != MONGOC_TOPOLOGY_BG_OFF); mongoc_client_pool_push (pool, client_a); mongoc_client_pool_push (pool, client_b); mongoc_client_pool_destroy (pool); } static void test_server_selection_try_once_option (void) { const char *uri_strings[3] = { "mongodb://a", "mongodb://a/?serverSelectionTryOnce=true", "mongodb://a/?serverSelectionTryOnce=false" }; unsigned long i; mongoc_client_t *client; mongoc_uri_t *uri; mongoc_client_pool_t *pool; /* try_once is on by default for non-pooled, can be turned off */ client = mongoc_client_new (uri_strings[0]); assert (client->topology->server_selection_try_once); mongoc_client_destroy (client); client = mongoc_client_new (uri_strings[1]); assert (client->topology->server_selection_try_once); mongoc_client_destroy (client); client = mongoc_client_new (uri_strings[2]); assert (! client->topology->server_selection_try_once); mongoc_client_destroy (client); /* off for pooled clients, can't be enabled */ for (i = 0; i < sizeof (uri_strings) / sizeof (char *); i++) { uri = mongoc_uri_new ("mongodb://a"); pool = mongoc_client_pool_new (uri); client = mongoc_client_pool_pop (pool); assert (!client->topology->server_selection_try_once); mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); mongoc_uri_destroy (uri); } } static void _test_server_selection (bool try_once) { mock_server_t *server; char *secondary_response; char *primary_response; mongoc_uri_t *uri; mongoc_client_t *client; mongoc_read_prefs_t *primary_pref; future_t *future; bson_error_t error; request_t *request; mongoc_server_description_t *sd; server = mock_server_new (); mock_server_set_request_timeout_msec (server, 600); mock_server_run (server); secondary_response = bson_strdup_printf ( "{'ok': 1, " " 'ismaster': false," " 'secondary': true," " 'setName': 'rs'," " 'hosts': ['%s']}", mock_server_get_host_and_port (server)); primary_response = bson_strdup_printf ( "{'ok': 1, " " 'ismaster': true," " 'setName': 'rs'," " 'hosts': ['%s']}", mock_server_get_host_and_port (server)); uri = mongoc_uri_copy (mock_server_get_uri (server)); mongoc_uri_set_option_as_utf8 (uri, "replicaSet", "rs"); mongoc_uri_set_option_as_int32 (uri, "heartbeatFrequencyMS", 500); mongoc_uri_set_option_as_int32 (uri, "serverSelectionTimeoutMS", 100); if (!try_once) { /* serverSelectionTryOnce is on by default */ mongoc_uri_set_option_as_bool (uri, "serverSelectionTryOnce", false); } client = mongoc_client_new_from_uri (uri); primary_pref = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); /* no primary, selection fails after one try */ future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); request = mock_server_receives_ismaster (server); assert(request); mock_server_replies_simple (request, secondary_response); request_destroy (request); /* the selection timeout is 100 ms, and we can't rescan until a half second * passes, so selection fails without another ismaster call */ assert (!mock_server_receives_ismaster (server)); /* selection fails */ assert (!future_get_mongoc_server_description_ptr (future)); ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_SERVER_SELECTION); ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_SERVER_SELECTION_FAILURE); if (try_once) { ASSERT_CMPSTR ("No suitable servers found (`serverselectiontryonce` set)", error.message); } else { ASSERT_CMPSTR ("No suitable servers found: `minheartbeatfrequencyms` not reached yet", error.message); } assert (client->topology->stale); future_destroy (future); _mongoc_usleep (510 * 1000); /* one heartbeat, plus a few milliseconds */ /* second selection, now we try ismaster again */ future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); request = mock_server_receives_ismaster (server); assert (request); /* the secondary is now primary, selection succeeds */ mock_server_replies_simple (request, primary_response); sd = future_get_mongoc_server_description_ptr (future); assert (sd); assert (!client->topology->stale); request_destroy (request); future_destroy (future); mongoc_server_description_destroy (sd); mongoc_read_prefs_destroy (primary_pref); mongoc_client_destroy (client); mongoc_uri_destroy (uri); bson_free (secondary_response); bson_free (primary_response); mock_server_destroy (server); } static void test_server_selection_try_once (void) { _test_server_selection (true); } static void test_server_selection_try_once_false (void) { _test_server_selection (false); } static void host_list_init (mongoc_host_list_t *host_list, int family, const char *host, uint16_t port) { memset (host_list, 0, sizeof *host_list); host_list->family = family; bson_snprintf (host_list->host, sizeof host_list->host, "%s", host); bson_snprintf (host_list->host_and_port, sizeof host_list->host_and_port, "%s:%hu", host, port); } static void test_topology_invalidate_server (void) { mongoc_server_description_t *fake_sd; mongoc_server_description_t *sd; mongoc_topology_description_t *td; mongoc_client_t *client; bson_error_t error; mongoc_host_list_t fake_host_list; uint32_t fake_id = 42; uint32_t id; mongoc_server_stream_t *server_stream; host_list_init (&fake_host_list, AF_INET, "fakeaddress", 27033); client = test_framework_client_new (); assert (client); td = &client->topology->description; /* call explicitly */ server_stream = mongoc_cluster_stream_for_reads (&client->cluster, NULL, &error); ASSERT_OR_PRINT (server_stream, error); id = server_stream->sd->id; sd = (mongoc_server_description_t *)mongoc_set_get(td->servers, id); assert (sd); assert (sd->type == MONGOC_SERVER_STANDALONE || sd->type == MONGOC_SERVER_RS_PRIMARY || sd->type == MONGOC_SERVER_MONGOS); mongoc_topology_invalidate_server (client->topology, id); sd = (mongoc_server_description_t *)mongoc_set_get(td->servers, id); assert (sd); assert (sd->type == MONGOC_SERVER_UNKNOWN); fake_sd = (mongoc_server_description_t *)bson_malloc0 (sizeof (*fake_sd)); /* insert a 'fake' server description and ensure that it is invalidated by driver */ mongoc_server_description_init (fake_sd, fake_host_list.host_and_port, fake_id); fake_sd->type = MONGOC_SERVER_STANDALONE; mongoc_set_add(td->servers, fake_id, fake_sd); mongoc_topology_scanner_add_and_scan (client->topology->scanner, &fake_host_list, fake_id, MONGOC_DEFAULT_CONNECTTIMEOUTMS); assert (!mongoc_cluster_stream_for_server (&client->cluster, fake_id, true, &error)); sd = (mongoc_server_description_t *)mongoc_set_get(td->servers, fake_id); assert (sd); assert (sd->type == MONGOC_SERVER_UNKNOWN); mongoc_server_stream_cleanup (server_stream); mongoc_client_destroy (client); } static void test_invalid_cluster_node (void) { mongoc_client_pool_t *pool; mongoc_cluster_node_t *cluster_node; mongoc_topology_scanner_node_t *scanner_node; bson_error_t error; mongoc_client_t *client; mongoc_cluster_t *cluster; mongoc_server_stream_t *server_stream; uint32_t id; /* use client pool, this test is only valid when multi-threaded */ pool = test_framework_client_pool_new (); client = mongoc_client_pool_pop (pool); cluster = &client->cluster; _mongoc_usleep (100 * 1000); /* load stream into cluster */ server_stream = mongoc_cluster_stream_for_reads (&client->cluster, NULL, &error); ASSERT_OR_PRINT (server_stream, error); id = server_stream->sd->id; mongoc_server_stream_cleanup (server_stream); cluster_node = (mongoc_cluster_node_t *)mongoc_set_get (cluster->nodes, id); scanner_node = mongoc_topology_scanner_get_node (client->topology->scanner, id); assert (cluster_node); assert (scanner_node); assert (cluster_node->stream); ASSERT_CMPINT64 (cluster_node->timestamp, >, scanner_node->timestamp); /* update the scanner node's timestamp */ _mongoc_usleep (1000 * 1000); scanner_node->timestamp = bson_get_monotonic_time (); ASSERT_CMPINT64 (cluster_node->timestamp, <, scanner_node->timestamp); _mongoc_usleep (1000 * 1000); /* cluster discards node and creates new one */ server_stream = mongoc_cluster_stream_for_server (&client->cluster, id, true, &error); ASSERT_OR_PRINT (server_stream, error); cluster_node = (mongoc_cluster_node_t *)mongoc_set_get (cluster->nodes, id); ASSERT_CMPINT64 (cluster_node->timestamp, >, scanner_node->timestamp); mongoc_server_stream_cleanup (server_stream); mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } static void test_max_wire_version_race_condition (void) { mongoc_topology_scanner_node_t *scanner_node; mongoc_server_description_t *sd; mongoc_database_t *database; mongoc_client_pool_t *pool; mongoc_client_t *client; bson_error_t error; mongoc_server_stream_t *server_stream; uint32_t id; /* connect directly and add our user, test is only valid with auth */ client = test_framework_client_new (); database = mongoc_client_get_database(client, "test"); mongoc_database_remove_user (database, "pink", &error); ASSERT_OR_PRINT (1 == mongoc_database_add_user ( database, "pink", "panther", NULL, NULL, &error), error); mongoc_database_destroy (database); mongoc_client_destroy (client); /* use client pool, test is only valid when multi-threaded */ pool = test_framework_client_pool_new (); client = mongoc_client_pool_pop (pool); /* load stream into cluster */ server_stream = mongoc_cluster_stream_for_reads (&client->cluster, NULL, &error); ASSERT_OR_PRINT (server_stream, error); id = server_stream->sd->id; mongoc_server_stream_cleanup (server_stream); /* "disconnect": invalidate timestamp and reset server description */ scanner_node = mongoc_topology_scanner_get_node (client->topology->scanner, id); assert (scanner_node); scanner_node->timestamp = bson_get_monotonic_time (); sd = (mongoc_server_description_t *)mongoc_set_get (client->topology->description.servers, id); assert (sd); mongoc_server_description_reset (sd); /* new stream, ensure that we can still auth with cached wire version */ server_stream = mongoc_cluster_stream_for_server (&client->cluster, id, true, &error); ASSERT_OR_PRINT (server_stream, error); assert (server_stream); mongoc_server_stream_cleanup (server_stream); mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } static void test_cooldown_standalone (void) { mock_server_t *server; mongoc_uri_t *uri; mongoc_client_t *client; mongoc_read_prefs_t *primary_pref; future_t *future; bson_error_t error; request_t *request; mongoc_server_description_t *sd; server = mock_server_new (); mock_server_set_request_timeout_msec (server, 100); mock_server_run (server); uri = mongoc_uri_copy (mock_server_get_uri (server)); /* anything less than minHeartbeatFrequencyMS=500 is irrelevant */ mongoc_uri_set_option_as_int32 (uri, "serverSelectionTimeoutMS", 100); client = mongoc_client_new_from_uri (uri); primary_pref = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); /* first ismaster fails, selection fails */ future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); request = mock_server_receives_ismaster (server); assert (request); mock_server_hangs_up (request); assert (!future_get_mongoc_server_description_ptr (future)); request_destroy (request); future_destroy (future); _mongoc_usleep (1000 * 1000); /* 1 second */ /* second selection doesn't try to call ismaster: we're in cooldown */ future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); assert (!mock_server_receives_ismaster (server)); /* no ismaster call */ assert (!future_get_mongoc_server_description_ptr (future)); future_destroy (future); _mongoc_usleep (5100 * 1000); /* 5.1 seconds */ /* cooldown ends, now we try ismaster again, this time succeeding */ future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); request = mock_server_receives_ismaster (server); /* not in cooldown now */ assert (request); mock_server_replies_simple (request, "{'ok': 1, 'ismaster': true}"); sd = future_get_mongoc_server_description_ptr (future); assert (sd); request_destroy (request); future_destroy (future); mongoc_server_description_destroy (sd); mongoc_read_prefs_destroy (primary_pref); mongoc_client_destroy (client); mongoc_uri_destroy (uri); mock_server_destroy (server); } static void test_cooldown_rs (void) { mock_server_t *servers[2]; /* two secondaries, no primary */ char *uri_str; int i; mongoc_client_t *client; mongoc_read_prefs_t *primary_pref; char *secondary_response; char *primary_response; future_t *future; bson_error_t error; request_t *request; mongoc_server_description_t *sd; for (i = 0; i < 2; i++) { servers[i] = mock_server_new (); mock_server_set_request_timeout_msec (servers[i], 600); mock_server_run (servers[i]); } uri_str = bson_strdup_printf ( "mongodb://localhost:%hu/?replicaSet=rs" "&serverSelectionTimeoutMS=100" "&connectTimeoutMS=100", mock_server_get_port (servers[0])); client = mongoc_client_new (uri_str); primary_pref = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); secondary_response = bson_strdup_printf ( "{'ok': 1, 'ismaster': false, 'secondary': true, 'setName': 'rs'," " 'hosts': ['localhost:%hu', 'localhost:%hu']}", mock_server_get_port (servers[0]), mock_server_get_port (servers[1])); primary_response = bson_strdup_printf ( "{'ok': 1, 'ismaster': true, 'setName': 'rs'," " 'hosts': ['localhost:%hu', 'localhost:%hu']}", mock_server_get_port (servers[0]), mock_server_get_port (servers[1])); /* server 0 is a secondary. */ future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); request = mock_server_receives_ismaster (servers[0]); assert (request); mock_server_replies_simple (request, secondary_response); request_destroy (request); /* server 0 told us about server 1. we check it immediately but it's down. */ request = mock_server_receives_ismaster (servers[1]); assert (request); mock_server_hangs_up (request); request_destroy (request); /* selection fails. */ assert (!future_get_mongoc_server_description_ptr (future)); future_destroy (future); _mongoc_usleep (1000 * 1000); /* 1 second */ /* second selection doesn't try ismaster on server 1: it's in cooldown */ future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); request = mock_server_receives_ismaster (servers[0]); assert (request); mock_server_replies_simple (request, secondary_response); request_destroy (request); assert (!mock_server_receives_ismaster (servers[1])); /* no ismaster call */ /* still no primary */ assert (!future_get_mongoc_server_description_ptr (future)); future_destroy (future); _mongoc_usleep (5100 * 1000); /* 5.1 seconds */ /* cooldown ends, now we try ismaster on server 1, this time succeeding */ future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); request = mock_server_receives_ismaster (servers[1]); assert (request); mock_server_replies_simple (request, primary_response); request_destroy (request); /* server 0 doesn't need to respond */ sd = future_get_mongoc_server_description_ptr (future); assert (sd); future_destroy (future); mongoc_server_description_destroy (sd); mongoc_read_prefs_destroy (primary_pref); mongoc_client_destroy (client); bson_free (secondary_response); bson_free (primary_response); bson_free (uri_str); mock_server_destroy (servers[0]); } static void _test_connect_timeout (bool pooled, bool try_once) { const int32_t connect_timeout_ms = 200; const int32_t server_selection_timeout_ms = 10 * 1000; /* 10 seconds */ mock_server_t *servers[2]; int i; char *secondary_response; char *uri_str; mongoc_uri_t *uri; mongoc_client_pool_t *pool = NULL; mongoc_client_t *client; mongoc_read_prefs_t *primary_pref; future_t *future; int64_t start; int64_t server0_last_ismaster; int64_t duration_usec; int64_t expected_duration_usec; bool server0_in_cooldown; bson_error_t error; request_t *request; assert (!(pooled && try_once)); /* not supported */ for (i = 0; i < 2; i++) { servers[i] = mock_server_new (); mock_server_run (servers[i]); }; secondary_response = bson_strdup_printf ("{'ok': 1," " 'ismaster': false," " 'secondary': true," " 'setName': 'rs'}"); uri_str = bson_strdup_printf ( "mongodb://localhost:%hu,localhost:%hu/" "?replicaSet=rs&connectTimeoutMS=%d&serverSelectionTimeoutMS=%d", mock_server_get_port (servers[0]), mock_server_get_port (servers[1]), connect_timeout_ms, server_selection_timeout_ms); uri = mongoc_uri_new (uri_str); assert (uri); if (!pooled && !try_once) { /* override default */ mongoc_uri_set_option_as_bool (uri, "serverSelectionTryOnce", false); } if (pooled) { pool = mongoc_client_pool_new (uri); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new_from_uri (uri); } primary_pref = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); /* start waiting for a server */ future = future_topology_select (client->topology, MONGOC_SS_READ, primary_pref, 15, &error); server0_last_ismaster = start = bson_get_monotonic_time (); /* server 0 doesn't respond */ request = mock_server_receives_ismaster (servers[0]); assert (request); request_destroy (request); /* server 1 is a secondary */ request = mock_server_receives_ismaster (servers[1]); mock_server_replies_simple (request, secondary_response); request_destroy (request); if (!try_once) { /* driver retries every minHeartbeatFrequencyMS + connectTimeoutMS */ server0_in_cooldown = true; expected_duration_usec = 0; while (expected_duration_usec < server_selection_timeout_ms) { request = mock_server_receives_ismaster (servers[1]); mock_server_replies_simple (request, secondary_response); request_destroy (request); duration_usec = bson_get_monotonic_time () - start; expected_duration_usec += 1000 * ( connect_timeout_ms + MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS); ASSERT_ALMOST_EQUAL (duration_usec, expected_duration_usec); /* single client puts server 0 in cooldown for 5 sec */ if (pooled || !server0_in_cooldown) { request = mock_server_receives_ismaster (servers[0]); assert (request); server0_last_ismaster = bson_get_monotonic_time (); request_destroy (request); /* don't respond */ } server0_in_cooldown = (bson_get_monotonic_time () - server0_last_ismaster) < 5 * 1000 * 1000; } } /* selection fails */ assert (!future_get_mongoc_server_description_ptr (future)); future_destroy (future); duration_usec = bson_get_monotonic_time () - start; if (try_once) { ASSERT_ALMOST_EQUAL (duration_usec / 1000, connect_timeout_ms); } else { ASSERT_ALMOST_EQUAL (duration_usec / 1000, server_selection_timeout_ms); } if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } mongoc_read_prefs_destroy (primary_pref); mongoc_uri_destroy (uri); bson_free (uri_str); bson_free (secondary_response); for (i = 0; i < 2; i++) { mock_server_destroy (servers[i]); }; } static void test_connect_timeout_pooled (void) { _test_connect_timeout (true, false); } static void test_connect_timeout_single(void) { _test_connect_timeout (false, true); } static void test_connect_timeout_try_once_false(void) { _test_connect_timeout (false, false); } static void test_multiple_selection_errors (void) { const char *uri = "mongodb://doesntexist,example.com:2/?replicaSet=rs" "&connectTimeoutMS=100"; mongoc_client_t *client; bson_t reply; bson_error_t error; client = mongoc_client_new (uri); mongoc_client_command_simple (client, "test", tmp_bson ("{'ping': 1}"), NULL, &reply, &error); ASSERT_CMPINT (MONGOC_ERROR_SERVER_SELECTION, ==, error.domain); ASSERT_CMPINT (MONGOC_ERROR_SERVER_SELECTION_FAILURE, ==, error.code); /* Like: * "No suitable servers found (`serverselectiontryonce` set): * [Failed to resolve 'doesntexist'] [connection error]" */ ASSERT_CONTAINS (error.message, "No suitable servers found"); ASSERT_CONTAINS (error.message, "[connection error calling ismaster on 'example.com:2']"); ASSERT_CONTAINS (error.message, "[Failed to resolve 'doesntexist']"); mongoc_client_destroy (client); } static void test_invalid_server_id (void) { mongoc_client_t *client; bson_error_t error; client = test_framework_client_new (); BSON_ASSERT (!mongoc_topology_server_by_id (client->topology, 99999, &error)); ASSERT_STARTSWITH (error.message, "Could not find description for node"); mongoc_client_destroy (client); } void test_topology_install (TestSuite *suite) { TestSuite_Add (suite, "/Topology/client_creation", test_topology_client_creation); TestSuite_Add (suite, "/Topology/client_pool_creation", test_topology_client_pool_creation); TestSuite_Add (suite, "/Topology/server_selection_try_once_option", test_server_selection_try_once_option); TestSuite_Add (suite, "/Topology/server_selection_try_once", test_server_selection_try_once); TestSuite_Add (suite, "/Topology/server_selection_try_once_false", test_server_selection_try_once_false); TestSuite_Add (suite, "/Topology/invalidate_server", test_topology_invalidate_server); TestSuite_Add (suite, "/Topology/invalid_cluster_node", test_invalid_cluster_node); TestSuite_Add (suite, "/Topology/max_wire_version_race_condition", test_max_wire_version_race_condition); TestSuite_Add (suite, "/Topology/cooldown/standalone", test_cooldown_standalone); TestSuite_Add (suite, "/Topology/cooldown/rs", test_cooldown_rs); TestSuite_Add (suite, "/Topology/connect_timeout/pooled", test_connect_timeout_pooled); TestSuite_Add (suite, "/Topology/connect_timeout/single/try_once", test_connect_timeout_single); TestSuite_Add (suite, "/Topology/connect_timeout/single/try_once_false", test_connect_timeout_try_once_false); TestSuite_Add (suite, "/Topology/multiple_selection_errors", test_multiple_selection_errors); TestSuite_Add (suite, "/Topology/invalid_server_id", test_invalid_server_id); } libmongoc-1.3.1/tests/test-mongoc-uri.c000066400000000000000000000733061264720626300200500ustar00rootroot00000000000000#include #include "mongoc-client-private.h" #include "mongoc-uri-private.h" #include "mongoc-host-list-private.h" #include "TestSuite.h" #include "test-libmongoc.h" #define ASSERT_SUPPRESS(x) \ do { \ suppress_one_message (); \ ASSERT (x); \ } while (0) static void test_mongoc_uri_new (void) { const mongoc_host_list_t *hosts; const bson_t *options; const bson_t *credentials; const bson_t *read_prefs_tags; const mongoc_read_prefs_t *read_prefs; bson_t properties; mongoc_uri_t *uri; bson_iter_t iter; bson_iter_t child; /* bad uris */ ASSERT(!mongoc_uri_new("mongodb://")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://\x80")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://localhost/\x80")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://localhost:\x80/")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://localhost/?ipv6=\x80")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://localhost/?foo=\x80")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://localhost/?\x80=bar")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://\x80:pass@localhost")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://user:\x80@localhost")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/?" "authMechanism=\x80")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/?" "authMechanism=GSSAPI" "&authMechanismProperties=SERVICE_NAME:\x80")); ASSERT_SUPPRESS(!mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/?" "authMechanism=GSSAPI" "&authMechanismProperties=\x80:mongodb")); ASSERT(!mongoc_uri_new("mongodb://::")); ASSERT(!mongoc_uri_new("mongodb://localhost::27017")); ASSERT(!mongoc_uri_new("mongodb://localhost,localhost::")); ASSERT(!mongoc_uri_new("mongodb://local1,local2,local3/d?k")); ASSERT(!mongoc_uri_new("")); ASSERT(!mongoc_uri_new("mongo://localhost:27017")); ASSERT(!mongoc_uri_new("mongodb://localhost::27017")); ASSERT(!mongoc_uri_new("mongodb://localhost::27017/")); ASSERT(!mongoc_uri_new("mongodb://localhost::27017,abc")); ASSERT(!mongoc_uri_new("mongodb://localhost:-1")); ASSERT(!mongoc_uri_new("mongodb://localhost:65536")); ASSERT(!mongoc_uri_new("mongodb://localhost:foo")); ASSERT(!mongoc_uri_new("mongodb://localhost:65536/")); ASSERT(!mongoc_uri_new("mongodb://localhost:0/")); ASSERT(!mongoc_uri_new("mongodb://[::1]:-1")); ASSERT(!mongoc_uri_new("mongodb://[::1]:foo")); ASSERT(!mongoc_uri_new("mongodb://[::1]:65536")); ASSERT(!mongoc_uri_new("mongodb://[::1]:65536/")); ASSERT(!mongoc_uri_new("mongodb://[::1]:0/")); uri = mongoc_uri_new("mongodb://[::1]:27888,[::2]:27999/?ipv6=true&safe=true"); assert (uri); hosts = mongoc_uri_get_hosts(uri); assert (hosts); ASSERT_CMPSTR (hosts->host, "::1"); assert (hosts->port == 27888); ASSERT_CMPSTR (hosts->host_and_port, "[::1]:27888"); mongoc_uri_destroy (uri); uri = mongoc_uri_new("mongodb:///tmp/mongodb-27017.sock/?"); ASSERT(uri); mongoc_uri_destroy(uri); /* should normalize to lowercase */ uri = mongoc_uri_new ("mongodb://cRaZyHoStNaMe"); assert (uri); hosts = mongoc_uri_get_hosts (uri); assert (hosts); ASSERT_CMPSTR (hosts->host, "crazyhostname"); mongoc_uri_destroy (uri); uri = mongoc_uri_new("mongodb://localhost/?"); ASSERT(uri); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://localhost:27017/test?q=1"); ASSERT(uri); hosts = mongoc_uri_get_hosts(uri); ASSERT(hosts); ASSERT(!hosts->next); ASSERT_CMPSTR(hosts->host, "localhost"); ASSERT_CMPINT(hosts->port, ==, 27017); ASSERT_CMPSTR(hosts->host_and_port, "localhost:27017"); ASSERT_CMPSTR(mongoc_uri_get_database(uri), "test"); options = mongoc_uri_get_options(uri); ASSERT(options); ASSERT(bson_iter_init_find(&iter, options, "q")); ASSERT_CMPSTR(bson_iter_utf8(&iter, NULL), "1"); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://local1,local2:999,local3?q=1"); ASSERT(uri); hosts = mongoc_uri_get_hosts(uri); ASSERT(hosts); ASSERT(hosts->next); ASSERT(hosts->next->next); ASSERT(!hosts->next->next->next); ASSERT_CMPSTR(hosts->host, "local1"); ASSERT_CMPINT(hosts->port, ==, 27017); ASSERT_CMPSTR(hosts->next->host, "local2"); ASSERT_CMPINT(hosts->next->port, ==, 999); ASSERT_CMPSTR(hosts->next->next->host, "local3"); ASSERT_CMPINT(hosts->next->next->port, ==, 27017); options = mongoc_uri_get_options(uri); ASSERT(options); ASSERT(bson_iter_init_find(&iter, options, "q")); ASSERT_CMPSTR(bson_iter_utf8(&iter, NULL), "1"); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://localhost:27017/?readPreference=secondaryPreferred&readPreferenceTags=dc:ny&readPreferenceTags="); ASSERT(uri); read_prefs = mongoc_uri_get_read_prefs_t(uri); ASSERT(mongoc_read_prefs_get_mode(read_prefs) == MONGOC_READ_SECONDARY_PREFERRED); ASSERT(read_prefs); read_prefs_tags = mongoc_read_prefs_get_tags(read_prefs); ASSERT(read_prefs_tags); ASSERT_CMPINT(bson_count_keys(read_prefs_tags), ==, 2); ASSERT(bson_iter_init_find(&iter, read_prefs_tags, "0")); ASSERT(BSON_ITER_HOLDS_DOCUMENT(&iter)); ASSERT(bson_iter_recurse(&iter, &child)); ASSERT(bson_iter_next(&child)); ASSERT_CMPSTR(bson_iter_key(&child), "dc"); ASSERT_CMPSTR(bson_iter_utf8(&child, NULL), "ny"); ASSERT(!bson_iter_next(&child)); ASSERT(bson_iter_next(&iter)); ASSERT(BSON_ITER_HOLDS_DOCUMENT(&iter)); ASSERT(bson_iter_recurse(&iter, &child)); ASSERT(!bson_iter_next(&child)); ASSERT(!bson_iter_next(&iter)); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://localhost/a?slaveok=true&ssl=false&journal=true"); options = mongoc_uri_get_options(uri); ASSERT(options); ASSERT_CMPINT(bson_count_keys(options), ==, 3); ASSERT(bson_iter_init(&iter, options)); ASSERT(bson_iter_find_case(&iter, "slaveok")); ASSERT(BSON_ITER_HOLDS_BOOL(&iter)); ASSERT(bson_iter_bool(&iter)); ASSERT(bson_iter_find_case(&iter, "ssl")); ASSERT(BSON_ITER_HOLDS_BOOL(&iter)); ASSERT(!bson_iter_bool(&iter)); ASSERT(bson_iter_find_case(&iter, "journal")); ASSERT(BSON_ITER_HOLDS_BOOL(&iter)); ASSERT(bson_iter_bool(&iter)); ASSERT(!bson_iter_next(&iter)); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://localhost/?safe=false&journal=false"); options = mongoc_uri_get_options(uri); ASSERT(options); ASSERT_CMPINT(bson_count_keys(options), ==, 2); ASSERT(bson_iter_init(&iter, options)); ASSERT(bson_iter_find_case(&iter, "safe")); ASSERT(BSON_ITER_HOLDS_BOOL(&iter)); ASSERT(!bson_iter_bool(&iter)); ASSERT(bson_iter_find_case(&iter, "journal")); ASSERT(BSON_ITER_HOLDS_BOOL(&iter)); ASSERT(!bson_iter_bool(&iter)); ASSERT(!bson_iter_next(&iter)); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb:///tmp/mongodb-27017.sock/?ssl=false"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_hosts(uri)->host, "/tmp/mongodb-27017.sock"); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb:///tmp/mongodb-27017.sock,localhost:27017/?ssl=false"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_hosts(uri)->host, "/tmp/mongodb-27017.sock"); ASSERT_CMPSTR(mongoc_uri_get_hosts(uri)->next->host_and_port, "localhost:27017"); ASSERT(!mongoc_uri_get_hosts(uri)->next->next); mongoc_uri_destroy(uri); /* should assign port numbers to correct hosts */ uri = mongoc_uri_new("mongodb://host1,host2:30000/foo/"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_hosts(uri)->host_and_port, "host1:27017"); ASSERT_CMPSTR(mongoc_uri_get_hosts(uri)->next->host_and_port, "host2:30000"); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://localhost:27017,/tmp/mongodb-27017.sock/?ssl=false"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_hosts(uri)->host_and_port, "localhost:27017"); ASSERT_CMPSTR(mongoc_uri_get_hosts(uri)->next->host, "/tmp/mongodb-27017.sock"); ASSERT(!mongoc_uri_get_hosts(uri)->next->next); mongoc_uri_destroy(uri); /* should use the authSource over db when both are specified */ uri = mongoc_uri_new("mongodb://christian:secret@localhost:27017/foo/?authSource=abcd"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_username(uri), "christian"); ASSERT_CMPSTR(mongoc_uri_get_password(uri), "secret"); ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "abcd"); mongoc_uri_destroy(uri); /* should use the default auth source and mechanism */ uri = mongoc_uri_new("mongodb://christian:secret@localhost:27017"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "admin"); ASSERT(!mongoc_uri_get_auth_mechanism(uri)); mongoc_uri_destroy(uri); /* should use the db when no authSource is specified */ uri = mongoc_uri_new("mongodb://user:password@localhost/foo"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "foo"); mongoc_uri_destroy(uri); /* should recognize an empty password */ uri = mongoc_uri_new("mongodb://samantha:@localhost"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_username(uri), "samantha"); ASSERT_CMPSTR(mongoc_uri_get_password(uri), ""); mongoc_uri_destroy(uri); /* should recognize no password */ uri = mongoc_uri_new("mongodb://christian@localhost:27017"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_username(uri), "christian"); ASSERT(!mongoc_uri_get_password(uri)); mongoc_uri_destroy(uri); /* should recognize a url escaped character in the username */ uri = mongoc_uri_new("mongodb://christian%40realm:pwd@localhost:27017"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_username(uri), "christian@realm"); mongoc_uri_destroy(uri); /* while you shouldn't do this, lets test for it */ uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017/db%2ename"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_database(uri), "db.name"); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017/db%2Ename"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_database(uri), "db.name"); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017/?abcd=%20"); ASSERT(uri); options = mongoc_uri_get_options(uri); ASSERT(options); ASSERT(bson_iter_init_find(&iter, options, "abcd")); ASSERT(BSON_ITER_HOLDS_UTF8(&iter)); ASSERT_CMPSTR(bson_iter_utf8(&iter, NULL), " "); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://christian%40realm@[::6]:27017/?abcd=%20"); ASSERT(uri); options = mongoc_uri_get_options(uri); ASSERT(options); ASSERT(bson_iter_init_find(&iter, options, "abcd")); ASSERT(BSON_ITER_HOLDS_UTF8(&iter)); ASSERT_CMPSTR(bson_iter_utf8(&iter, NULL), " "); mongoc_uri_destroy(uri); /* GSSAPI-specific options */ /* should recognize the GSSAPI mechanism, and use $external as source */ uri = mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/?authMechanism=GSSAPI"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "GSSAPI"); /*ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "$external");*/ mongoc_uri_destroy(uri); /* use $external as source when db is specified */ uri = mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/foo/?authMechanism=GSSAPI"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "$external"); mongoc_uri_destroy(uri); /* should not accept authSource other than $external */ ASSERT(!mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/foo/?authMechanism=GSSAPI&authSource=bar")); /* should accept authMechanismProperties */ uri = mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/?authMechanism=GSSAPI" "&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true"); ASSERT(uri); credentials = mongoc_uri_get_credentials(uri); ASSERT(credentials); ASSERT(mongoc_uri_get_mechanism_properties(uri, &properties)); assert (bson_iter_init_find_case (&iter, &properties, "SERVICE_NAME") && BSON_ITER_HOLDS_UTF8 (&iter) && (0 == strcmp (bson_iter_utf8 (&iter, NULL), "other"))); assert (bson_iter_init_find_case (&iter, &properties, "CANONICALIZE_HOST_NAME") && BSON_ITER_HOLDS_UTF8 (&iter) && (0 == strcmp (bson_iter_utf8 (&iter, NULL), "true"))); mongoc_uri_destroy(uri); /* reverse order of arguments to ensure parsing still succeeds */ uri = mongoc_uri_new("mongodb://user@localhost/" "?authMechanismProperties=SERVICE_NAME:other" "&authMechanism=GSSAPI"); ASSERT(uri); mongoc_uri_destroy(uri); /* deprecated gssapiServiceName option */ uri = mongoc_uri_new("mongodb://christian%40realm.cc@localhost:27017/?authMechanism=GSSAPI&gssapiServiceName=blah"); ASSERT(uri); options = mongoc_uri_get_options(uri); ASSERT(options); assert (0 == strcmp (mongoc_uri_get_auth_mechanism (uri), "GSSAPI")); assert (0 == strcmp (mongoc_uri_get_username (uri), "christian@realm.cc")); assert (bson_iter_init_find_case (&iter, options, "gssapiServiceName") && BSON_ITER_HOLDS_UTF8 (&iter) && (0 == strcmp (bson_iter_utf8 (&iter, NULL), "blah"))); mongoc_uri_destroy(uri); /* MONGODB-CR */ /* should recognize this mechanism */ uri = mongoc_uri_new("mongodb://user@localhost/?authMechanism=MONGODB-CR"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "MONGODB-CR"); mongoc_uri_destroy(uri); /* X509 */ /* should recognize this mechanism, and use $external as the source */ uri = mongoc_uri_new("mongodb://user@localhost/?authMechanism=MONGODB-X509"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "MONGODB-X509"); /*ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "$external");*/ mongoc_uri_destroy(uri); /* use $external as source when db is specified */ uri = mongoc_uri_new("mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality" "%2CST%3DmyState%2CC%3DmyCountry@localhost/foo/?authMechanism=MONGODB-X509"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "$external"); mongoc_uri_destroy(uri); /* should not accept authSource other than $external */ ASSERT(!mongoc_uri_new("mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality" "%2CST%3DmyState%2CC%3DmyCountry@localhost/foo/?authMechanism=MONGODB-X509&authSource=bar")); /* should recognize the encoded username */ uri = mongoc_uri_new("mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality" "%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_username(uri), "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry"); mongoc_uri_destroy(uri); /* PLAIN */ /* should recognize this mechanism */ uri = mongoc_uri_new("mongodb://user@localhost/?authMechanism=PLAIN"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "PLAIN"); mongoc_uri_destroy(uri); /* SCRAM-SHA1 */ /* should recognize this mechanism */ uri = mongoc_uri_new("mongodb://user@localhost/?authMechanism=SCRAM-SHA1"); ASSERT(uri); ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "SCRAM-SHA1"); mongoc_uri_destroy(uri); } static void test_mongoc_uri_functions (void) { mongoc_client_t *client; mongoc_uri_t *uri; mongoc_database_t *db; uri = mongoc_uri_new("mongodb://foo:bar@localhost:27017/baz?authSource=source"); ASSERT_CMPSTR(mongoc_uri_get_username(uri), "foo"); ASSERT_CMPSTR(mongoc_uri_get_password(uri), "bar"); ASSERT_CMPSTR(mongoc_uri_get_database(uri), "baz"); ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "source"); mongoc_uri_set_username (uri, "longer username that should work"); ASSERT_CMPSTR(mongoc_uri_get_username(uri), "longer username that should work"); mongoc_uri_set_password (uri, "longer password that should also work"); ASSERT_CMPSTR(mongoc_uri_get_password(uri), "longer password that should also work"); mongoc_uri_set_database (uri, "longer database that should work"); ASSERT_CMPSTR(mongoc_uri_get_database(uri), "longer database that should work"); ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "source"); mongoc_uri_set_auth_source (uri, "longer authsource that should work"); ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "longer authsource that should work"); ASSERT_CMPSTR(mongoc_uri_get_database(uri), "longer database that should work"); client = mongoc_client_new_from_uri (uri); mongoc_uri_destroy(uri); ASSERT_CMPSTR(mongoc_uri_get_username(client->uri), "longer username that should work"); ASSERT_CMPSTR(mongoc_uri_get_password(client->uri), "longer password that should also work"); ASSERT_CMPSTR(mongoc_uri_get_database(client->uri), "longer database that should work"); ASSERT_CMPSTR(mongoc_uri_get_auth_source(client->uri), "longer authsource that should work"); mongoc_client_destroy (client); uri = mongoc_uri_new("mongodb://localhost/?serverselectiontimeoutms=3&journal=true&wtimeoutms=42&canonicalizeHostname=false"); ASSERT_CMPINT(mongoc_uri_get_option_as_int32(uri, "serverselectiontimeoutms", 18), ==, 3); ASSERT(mongoc_uri_set_option_as_int32(uri, "serverselectiontimeoutms", 18)); ASSERT_CMPINT(mongoc_uri_get_option_as_int32(uri, "serverselectiontimeoutms", 19), ==, 18); ASSERT_CMPINT(mongoc_uri_get_option_as_int32(uri, "wtimeoutms", 18), ==, 42); ASSERT(mongoc_uri_set_option_as_int32(uri, "wtimeoutms", 18)); ASSERT_CMPINT(mongoc_uri_get_option_as_int32(uri, "wtimeoutms", 19), ==, 18); /* socketcheckintervalms isn't set, return our fallback */ ASSERT_CMPINT(mongoc_uri_get_option_as_int32(uri, "socketcheckintervalms", 123), ==, 123); ASSERT(mongoc_uri_set_option_as_int32(uri, "socketcheckintervalms", 18)); ASSERT_CMPINT(mongoc_uri_get_option_as_int32(uri, "socketcheckintervalms", 19), ==, 18); ASSERT(mongoc_uri_get_option_as_bool(uri, "journal", false)); ASSERT(!mongoc_uri_get_option_as_bool(uri, "canonicalizeHostname", true)); /* ssl isn't set, return out fallback */ ASSERT(mongoc_uri_get_option_as_bool(uri, "ssl", true)); client = mongoc_client_new_from_uri (uri); mongoc_uri_destroy(uri); ASSERT(mongoc_uri_get_option_as_bool(client->uri, "journal", false)); ASSERT(!mongoc_uri_get_option_as_bool(client->uri, "canonicalizeHostname", true)); /* ssl isn't set, return out fallback */ ASSERT(mongoc_uri_get_option_as_bool(client->uri, "ssl", true)); mongoc_client_destroy (client); uri = mongoc_uri_new("mongodb://localhost/"); ASSERT_CMPSTR(mongoc_uri_get_option_as_utf8(uri, "random", "default"), "default"); ASSERT(mongoc_uri_set_option_as_utf8(uri, "random", "value")); ASSERT_CMPSTR(mongoc_uri_get_option_as_utf8(uri, "random", "default"), "value"); mongoc_uri_destroy(uri); uri = mongoc_uri_new("mongodb://localhost/?sockettimeoutms=1&socketcheckintervalms=200"); ASSERT_CMPINT (1, ==, mongoc_uri_get_option_as_int32 (uri, "sockettimeoutms", 0)); ASSERT_CMPINT (200, ==, mongoc_uri_get_option_as_int32 (uri, "socketcheckintervalms", 0)); mongoc_uri_set_option_as_int32 (uri, "sockettimeoutms", 2); ASSERT_CMPINT (2, ==, mongoc_uri_get_option_as_int32 (uri, "sockettimeoutms", 0)); mongoc_uri_set_option_as_int32 (uri, "socketcheckintervalms", 202); ASSERT_CMPINT (202, ==, mongoc_uri_get_option_as_int32 (uri, "socketcheckintervalms", 0)); client = mongoc_client_new_from_uri (uri); ASSERT_CMPINT (2, ==, client->cluster.sockettimeoutms); ASSERT_CMPINT (202, ==, client->cluster.socketcheckintervalms); mongoc_client_destroy (client); mongoc_uri_destroy(uri); uri = mongoc_uri_new ("mongodb://host/dbname0"); ASSERT_CMPSTR (mongoc_uri_get_database (uri), "dbname0"); mongoc_uri_set_database (uri, "dbname1"); client = mongoc_client_new_from_uri (uri); db = mongoc_client_get_default_database (client); ASSERT_CMPSTR (mongoc_database_get_name (db), "dbname1"); mongoc_database_destroy (db); mongoc_client_destroy (client); mongoc_uri_destroy(uri); } #undef ASSERT_SUPPRESS static void test_mongoc_host_list_from_string (void) { mongoc_host_list_t host_list = { 0 }; ASSERT(_mongoc_host_list_from_string(&host_list, "localhost:27019")); ASSERT(!strcmp(host_list.host_and_port, "localhost:27019")); ASSERT(!strcmp(host_list.host, "localhost")); ASSERT(host_list.port == 27019); ASSERT(host_list.family == AF_INET); ASSERT(!host_list.next); } static void test_mongoc_uri_new_for_host_port (void) { mongoc_uri_t *uri; uri = mongoc_uri_new_for_host_port("uber", 555); ASSERT(uri); ASSERT(!strcmp("uber", mongoc_uri_get_hosts(uri)->host)); ASSERT(!strcmp("uber:555", mongoc_uri_get_hosts(uri)->host_and_port)); ASSERT(555 == mongoc_uri_get_hosts(uri)->port); mongoc_uri_destroy(uri); } static void test_mongoc_uri_unescape (void) { #define ASSERT_URIDECODE_STR(_s, _e) \ do { \ char *str = mongoc_uri_unescape(_s); \ ASSERT(!strcmp(str, _e)); \ bson_free(str); \ } while (0) #define ASSERT_URIDECODE_FAIL(_s) \ do { \ char *str = mongoc_uri_unescape(_s); \ ASSERT(!str); \ } while (0) ASSERT_URIDECODE_STR("", ""); ASSERT_URIDECODE_STR("%40", "@"); ASSERT_URIDECODE_STR("me%40localhost@localhost", "me@localhost@localhost"); ASSERT_URIDECODE_STR("%20", " "); ASSERT_URIDECODE_STR("%24%21%40%2A%26%5E%21%40%2A%23%26%5E%21%40%23%2A%26" "%5E%21%40%2A%23%26%5E%21%40%2A%26%23%5E%7D%7B%7D%7B" "%22%22%27%7D%7B%5B%5D%3C%3E%3F", "$!@*&^!@*#&^!@#*&^!@*#&^!@*&#^}{}{\"\"'}{[]<>?"); ASSERT_URIDECODE_FAIL("%"); ASSERT_URIDECODE_FAIL("%%"); ASSERT_URIDECODE_FAIL("%%%"); ASSERT_URIDECODE_FAIL("%FF"); ASSERT_URIDECODE_FAIL("%CC"); ASSERT_URIDECODE_FAIL("%00"); #undef ASSERT_URIDECODE_STR #undef ASSERT_URIDECODE_FAIL } typedef struct { const char *uri; bool parses; mongoc_read_mode_t mode; bson_t *tags; } read_prefs_test; static void test_mongoc_uri_read_prefs (void) { const mongoc_read_prefs_t *rp; mongoc_uri_t *uri; const read_prefs_test *t; int i; bson_t *tags_dcny = BCON_NEW( "0", "{", "dc", "ny", "}" ); bson_t *tags_dcny_empty = BCON_NEW( "0", "{", "dc", "ny", "}", "1", "{", "}" ); bson_t *tags_dcnyusessd_dcsf_empty = BCON_NEW( "0", "{", "dc", "ny", "use", "ssd", "}", "1", "{", "dc", "sf", "}", "2", "{", "}" ); bson_t *tags_empty = BCON_NEW( "0", "{", "}" ); const read_prefs_test tests [] = { { "mongodb://localhost/", true, MONGOC_READ_PRIMARY, NULL }, { "mongodb://localhost/?slaveOk=false", true, MONGOC_READ_PRIMARY, NULL }, { "mongodb://localhost/?slaveOk=true", true, MONGOC_READ_SECONDARY_PREFERRED, NULL }, { "mongodb://localhost/?readPreference=primary", true, MONGOC_READ_PRIMARY, NULL }, { "mongodb://localhost/?readPreference=primaryPreferred", true, MONGOC_READ_PRIMARY_PREFERRED, NULL }, { "mongodb://localhost/?readPreference=secondary", true, MONGOC_READ_SECONDARY, NULL }, { "mongodb://localhost/?readPreference=secondaryPreferred", true, MONGOC_READ_SECONDARY_PREFERRED, NULL }, { "mongodb://localhost/?readPreference=nearest", true, MONGOC_READ_NEAREST, NULL }, /* readPreference should take priority over slaveOk */ { "mongodb://localhost/?slaveOk=false&readPreference=secondary", true, MONGOC_READ_SECONDARY, NULL }, /* readPreferenceTags conflict with primary mode */ { "mongodb://localhost/?readPreferenceTags=", false }, { "mongodb://localhost/?readPreference=primary&readPreferenceTags=", false }, { "mongodb://localhost/?slaveOk=false&readPreferenceTags=", false }, { "mongodb://localhost/?readPreference=secondaryPreferred&readPreferenceTags=", true, MONGOC_READ_SECONDARY_PREFERRED, tags_empty }, { "mongodb://localhost/?readPreference=secondaryPreferred&readPreferenceTags=dc:ny", true, MONGOC_READ_SECONDARY_PREFERRED, tags_dcny }, { "mongodb://localhost/?readPreference=nearest&readPreferenceTags=dc:ny&readPreferenceTags=", true, MONGOC_READ_NEAREST, tags_dcny_empty }, { "mongodb://localhost/?readPreference=nearest&readPreferenceTags=dc:ny,use:ssd&readPreferenceTags=dc:sf&readPreferenceTags=", true, MONGOC_READ_NEAREST, tags_dcnyusessd_dcsf_empty }, { NULL } }; for (i = 0; tests[i].uri; i++) { t = &tests[i]; uri = mongoc_uri_new(t->uri); if (t->parses) { assert(uri); } else { assert(!uri); continue; } rp = mongoc_uri_get_read_prefs_t(uri); assert(rp); assert(t->mode == mongoc_read_prefs_get_mode(rp)); if (t->tags) { assert(bson_equal(t->tags, mongoc_read_prefs_get_tags(rp))); } mongoc_uri_destroy(uri); } bson_destroy(tags_dcny); bson_destroy(tags_dcny_empty); bson_destroy(tags_dcnyusessd_dcsf_empty); bson_destroy(tags_empty); } typedef struct { const char *uri; bool parses; int32_t w; const char *wtag; int32_t wtimeoutms; } write_concern_test; static void test_mongoc_uri_write_concern (void) { const mongoc_write_concern_t *wr; mongoc_uri_t *uri; const write_concern_test *t; int i; static const write_concern_test tests [] = { { "mongodb://localhost/?safe=false", true, MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED }, { "mongodb://localhost/?safe=true", true, 1 }, { "mongodb://localhost/?w=-1", true, MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED }, { "mongodb://localhost/?w=0", true, MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED }, { "mongodb://localhost/?w=1", true, 1 }, { "mongodb://localhost/?w=2", true, 2 }, { "mongodb://localhost/?w=majority", true, MONGOC_WRITE_CONCERN_W_MAJORITY }, { "mongodb://localhost/?w=10", true, 10 }, { "mongodb://localhost/?w=", true, MONGOC_WRITE_CONCERN_W_DEFAULT }, { "mongodb://localhost/?w=mytag", true, MONGOC_WRITE_CONCERN_W_TAG, "mytag" }, { "mongodb://localhost/?w=mytag&safe=false", true, MONGOC_WRITE_CONCERN_W_TAG, "mytag" }, { "mongodb://localhost/?w=1&safe=false", true, 1 }, { "mongodb://localhost/?journal=true", true, MONGOC_WRITE_CONCERN_W_DEFAULT }, { "mongodb://localhost/?w=0&journal=true", false, MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED }, { "mongodb://localhost/?w=-1&journal=true", false, MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED }, { "mongodb://localhost/?w=1&journal=true", true, 1 }, { "mongodb://localhost/?w=2&wtimeoutms=1000", true, 2, NULL, 1000 }, { "mongodb://localhost/?w=majority&wtimeoutms=1000", true, MONGOC_WRITE_CONCERN_W_MAJORITY, NULL, 1000 }, { "mongodb://localhost/?w=mytag&wtimeoutms=1000", true, MONGOC_WRITE_CONCERN_W_TAG, "mytag", 1000 }, { NULL } }; /* Suppress warnings from two invalid URIs ("journal" and "w" conflict) */ suppress_one_message(); suppress_one_message(); for (i = 0; tests [i].uri; i++) { t = &tests [i]; uri = mongoc_uri_new (t->uri); if (t->parses) { assert (uri); } else { assert (!uri); continue; } wr = mongoc_uri_get_write_concern (uri); assert (wr); assert (t->w == mongoc_write_concern_get_w (wr)); if (t->wtag) { assert (0 == strcmp (t->wtag, mongoc_write_concern_get_wtag (wr))); } if (t->wtimeoutms) { assert (t->wtimeoutms == mongoc_write_concern_get_wtimeout (wr)); } mongoc_uri_destroy (uri); } } static void test_mongoc_uri_read_concern (void) { const mongoc_read_concern_t *rc; mongoc_uri_t *uri; uri = mongoc_uri_new ("mongodb://localhost/?readConcernLevel=majority"); rc = mongoc_uri_get_read_concern (uri); ASSERT_CMPSTR (mongoc_read_concern_get_level (rc), "majority"); mongoc_uri_destroy (uri); uri = mongoc_uri_new ("mongodb://localhost/?readConcernLevel=" MONGOC_READ_CONCERN_LEVEL_MAJORITY); rc = mongoc_uri_get_read_concern (uri); ASSERT_CMPSTR (mongoc_read_concern_get_level (rc), "majority"); mongoc_uri_destroy (uri); uri = mongoc_uri_new ("mongodb://localhost/?readConcernLevel=local"); rc = mongoc_uri_get_read_concern (uri); ASSERT_CMPSTR (mongoc_read_concern_get_level (rc), "local"); mongoc_uri_destroy (uri); uri = mongoc_uri_new ("mongodb://localhost/?readConcernLevel=" MONGOC_READ_CONCERN_LEVEL_LOCAL); rc = mongoc_uri_get_read_concern (uri); ASSERT_CMPSTR (mongoc_read_concern_get_level (rc), "local"); mongoc_uri_destroy (uri); uri = mongoc_uri_new ("mongodb://localhost/?readConcernLevel=randomstuff"); rc = mongoc_uri_get_read_concern (uri); ASSERT_CMPSTR (mongoc_read_concern_get_level (rc), "randomstuff"); mongoc_uri_destroy (uri); uri = mongoc_uri_new ("mongodb://localhost/"); rc = mongoc_uri_get_read_concern (uri); ASSERT (mongoc_read_concern_get_level (rc) == NULL); mongoc_uri_destroy (uri); uri = mongoc_uri_new ("mongodb://localhost/?readConcernLevel="); rc = mongoc_uri_get_read_concern (uri); ASSERT_CMPSTR (mongoc_read_concern_get_level (rc), ""); mongoc_uri_destroy (uri); } void test_uri_install (TestSuite *suite) { TestSuite_Add (suite, "/Uri/new", test_mongoc_uri_new); TestSuite_Add (suite, "/Uri/new_for_host_port", test_mongoc_uri_new_for_host_port); TestSuite_Add (suite, "/Uri/unescape", test_mongoc_uri_unescape); TestSuite_Add (suite, "/Uri/read_prefs", test_mongoc_uri_read_prefs); TestSuite_Add (suite, "/Uri/read_concern", test_mongoc_uri_read_concern); TestSuite_Add (suite, "/Uri/write_concern", test_mongoc_uri_write_concern); TestSuite_Add (suite, "/HostList/from_string", test_mongoc_host_list_from_string); TestSuite_Add (suite, "/Uri/functions", test_mongoc_uri_functions); } libmongoc-1.3.1/tests/test-mongoc-usleep.c000066400000000000000000000007471264720626300205450ustar00rootroot00000000000000#include "mongoc-util-private.h" #include "TestSuite.h" static void test_mongoc_usleep_basic (void) { int64_t start; int64_t duration; start = bson_get_monotonic_time (); _mongoc_usleep (50 * 1000); /* 50 ms */ duration = bson_get_monotonic_time () - start; ASSERT_CMPINT ((int) duration, >, 0); ASSERT_CMPINT ((int) duration, <, 200 * 1000); } void test_usleep_install (TestSuite *suite) { TestSuite_Add (suite, "/Sleep/basic", test_mongoc_usleep_basic); } libmongoc-1.3.1/tests/test-mongoc-version.c000066400000000000000000000014621264720626300207300ustar00rootroot00000000000000#include #include "TestSuite.h" static void test_mongoc_version (void) { ASSERT_CMPINT (mongoc_get_major_version(), ==, MONGOC_MAJOR_VERSION); ASSERT_CMPINT (mongoc_get_minor_version(), ==, MONGOC_MINOR_VERSION); ASSERT_CMPINT (mongoc_get_micro_version(), ==, MONGOC_MICRO_VERSION); ASSERT_CMPSTR (mongoc_get_version(), MONGOC_VERSION_S); ASSERT (mongoc_check_version (MONGOC_MAJOR_VERSION, MONGOC_MINOR_VERSION, MONGOC_MICRO_VERSION)); ASSERT (!mongoc_check_version (MONGOC_MAJOR_VERSION, MONGOC_MINOR_VERSION + 1, MONGOC_MICRO_VERSION)); } void test_version_install (TestSuite *suite) { TestSuite_Add (suite, "/Version", test_mongoc_version); } libmongoc-1.3.1/tests/test-mongoc-write-concern.c000066400000000000000000000244341264720626300220260ustar00rootroot00000000000000#include #include #include "TestSuite.h" static void test_write_concern_basic (void) { mongoc_write_concern_t *write_concern; const bson_t *gle; const bson_t *bson; bson_iter_t iter; write_concern = mongoc_write_concern_new(); /* * Test defaults. */ ASSERT(write_concern); ASSERT(!mongoc_write_concern_get_fsync(write_concern)); ASSERT(!mongoc_write_concern_get_journal(write_concern)); ASSERT(mongoc_write_concern_get_w(write_concern) == MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(!mongoc_write_concern_get_wtimeout(write_concern)); ASSERT(!mongoc_write_concern_get_wmajority(write_concern)); mongoc_write_concern_set_fsync(write_concern, true); ASSERT(mongoc_write_concern_get_fsync(write_concern)); mongoc_write_concern_set_fsync(write_concern, false); ASSERT(!mongoc_write_concern_get_fsync(write_concern)); mongoc_write_concern_set_journal(write_concern, true); ASSERT(mongoc_write_concern_get_journal(write_concern)); mongoc_write_concern_set_journal(write_concern, false); ASSERT(!mongoc_write_concern_get_journal(write_concern)); /* * Test changes to w. */ mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_MAJORITY); ASSERT(mongoc_write_concern_get_wmajority(write_concern)); mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(!mongoc_write_concern_get_wmajority(write_concern)); mongoc_write_concern_set_wmajority(write_concern, 1000); ASSERT(mongoc_write_concern_get_wmajority(write_concern)); ASSERT(mongoc_write_concern_get_wtimeout(write_concern) == 1000); mongoc_write_concern_set_wtimeout(write_concern, 0); ASSERT(!mongoc_write_concern_get_wtimeout(write_concern)); mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(mongoc_write_concern_get_w(write_concern) == MONGOC_WRITE_CONCERN_W_DEFAULT); mongoc_write_concern_set_w(write_concern, 3); ASSERT(mongoc_write_concern_get_w(write_concern) == 3); /* * Check generated bson. */ mongoc_write_concern_set_fsync(write_concern, true); mongoc_write_concern_set_journal(write_concern, true); gle = _mongoc_write_concern_get_gle(write_concern); ASSERT(bson_iter_init_find(&iter, gle, "getlasterror") && BSON_ITER_HOLDS_INT32(&iter) && bson_iter_int32(&iter) == 1); ASSERT(bson_iter_init_find(&iter, gle, "fsync") && BSON_ITER_HOLDS_BOOL(&iter) && bson_iter_bool(&iter)); ASSERT(bson_iter_init_find(&iter, gle, "j") && BSON_ITER_HOLDS_BOOL(&iter) && bson_iter_bool(&iter)); ASSERT(bson_iter_init_find(&iter, gle, "w") && BSON_ITER_HOLDS_INT32(&iter) && bson_iter_int32(&iter) == 3); ASSERT(gle); bson = _mongoc_write_concern_get_bson(write_concern); ASSERT(!bson_iter_init_find(&iter, bson, "getlasterror")); ASSERT(bson_iter_init_find(&iter, bson, "fsync") && BSON_ITER_HOLDS_BOOL(&iter) && bson_iter_bool(&iter)); ASSERT(bson_iter_init_find(&iter, bson, "j") && BSON_ITER_HOLDS_BOOL(&iter) && bson_iter_bool(&iter)); ASSERT(bson_iter_init_find(&iter, bson, "w") && BSON_ITER_HOLDS_INT32(&iter) && bson_iter_int32(&iter) == 3); ASSERT(bson); mongoc_write_concern_destroy(write_concern); } static void test_write_concern_bson_omits_defaults (void) { mongoc_write_concern_t *write_concern; const bson_t *gle; const bson_t *bson; bson_iter_t iter; write_concern = mongoc_write_concern_new(); /* * Check generated bson. */ ASSERT(write_concern); gle = _mongoc_write_concern_get_gle(write_concern); ASSERT(bson_iter_init_find(&iter, gle, "getlasterror") && BSON_ITER_HOLDS_INT32(&iter) && bson_iter_int32(&iter) == 1); ASSERT(!bson_iter_init_find(&iter, gle, "fsync")); ASSERT(!bson_iter_init_find(&iter, gle, "j")); ASSERT(!bson_iter_init_find(&iter, gle, "w")); ASSERT(gle); bson = _mongoc_write_concern_get_bson(write_concern); ASSERT(!bson_iter_init_find(&iter, bson, "getlasterror")); ASSERT(!bson_iter_init_find(&iter, bson, "fsync")); ASSERT(!bson_iter_init_find(&iter, bson, "j")); ASSERT(!bson_iter_init_find(&iter, gle, "w")); ASSERT(bson); mongoc_write_concern_destroy(write_concern); } static void test_write_concern_bson_includes_false_fsync_and_journal (void) { mongoc_write_concern_t *write_concern; const bson_t *gle; const bson_t *bson; bson_iter_t iter; write_concern = mongoc_write_concern_new(); /* * Check generated bson. */ ASSERT(write_concern); mongoc_write_concern_set_fsync(write_concern, false); mongoc_write_concern_set_journal(write_concern, false); gle = _mongoc_write_concern_get_gle(write_concern); ASSERT(bson_iter_init_find(&iter, gle, "getlasterror") && BSON_ITER_HOLDS_INT32(&iter) && bson_iter_int32(&iter) == 1); ASSERT(bson_iter_init_find(&iter, gle, "fsync") && BSON_ITER_HOLDS_BOOL(&iter) && !bson_iter_bool(&iter)); ASSERT(bson_iter_init_find(&iter, gle, "j") && BSON_ITER_HOLDS_BOOL(&iter) && !bson_iter_bool(&iter)); ASSERT(!bson_iter_init_find(&iter, gle, "w")); ASSERT(gle); bson = _mongoc_write_concern_get_bson(write_concern); ASSERT(!bson_iter_init_find(&iter, bson, "getlasterror")); ASSERT(bson_iter_init_find(&iter, bson, "fsync") && BSON_ITER_HOLDS_BOOL(&iter) && !bson_iter_bool(&iter)); ASSERT(bson_iter_init_find(&iter, bson, "j") && BSON_ITER_HOLDS_BOOL(&iter) && !bson_iter_bool(&iter)); ASSERT(!bson_iter_init_find(&iter, bson, "w")); ASSERT(bson); mongoc_write_concern_destroy(write_concern); } static void test_write_concern_fsync_and_journal_gle_and_validity (void) { mongoc_write_concern_t *write_concern = mongoc_write_concern_new(); /* * Journal and fsync should imply GLE regardless of w; however, journal and * fsync logically conflict with w=0 and w=-1, so a write concern with such * a combination of options will be considered invalid. */ /* Default write concern needs GLE and is valid */ ASSERT(write_concern); ASSERT(_mongoc_write_concern_needs_gle(write_concern)); ASSERT(_mongoc_write_concern_is_valid(write_concern)); /* w=0 does not need GLE and is valid */ mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED); ASSERT(!_mongoc_write_concern_needs_gle(write_concern)); ASSERT(_mongoc_write_concern_is_valid(write_concern)); /* fsync=true needs GLE, but it conflicts with w=0 */ mongoc_write_concern_set_fsync(write_concern, true); ASSERT(_mongoc_write_concern_needs_gle(write_concern)); ASSERT(!_mongoc_write_concern_is_valid(write_concern)); mongoc_write_concern_set_fsync(write_concern, false); /* journal=true needs GLE, but it conflicts with w=0 */ mongoc_write_concern_set_journal(write_concern, true); ASSERT(_mongoc_write_concern_needs_gle(write_concern)); ASSERT(!_mongoc_write_concern_is_valid(write_concern)); mongoc_write_concern_set_journal(write_concern, false); /* w=-1 does not need GLE and is valid */ mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED); ASSERT(!_mongoc_write_concern_needs_gle(write_concern)); ASSERT(_mongoc_write_concern_is_valid(write_concern)); /* fsync=true needs GLE, but it conflicts with w=-1 */ mongoc_write_concern_set_fsync(write_concern, true); ASSERT(_mongoc_write_concern_needs_gle(write_concern)); ASSERT(!_mongoc_write_concern_is_valid(write_concern)); /* journal=true needs GLE, but it conflicts with w=-1 */ mongoc_write_concern_set_fsync(write_concern, false); mongoc_write_concern_set_journal(write_concern, true); ASSERT(_mongoc_write_concern_needs_gle(write_concern)); /* fsync=true with w=default needs GLE and is valid */ mongoc_write_concern_set_journal(write_concern, false); mongoc_write_concern_set_fsync(write_concern, true); mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(_mongoc_write_concern_needs_gle(write_concern)); ASSERT(_mongoc_write_concern_is_valid(write_concern)); /* journal=true with w=default needs GLE and is valid */ mongoc_write_concern_set_journal(write_concern, false); mongoc_write_concern_set_fsync(write_concern, true); mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(_mongoc_write_concern_needs_gle(write_concern)); ASSERT(_mongoc_write_concern_is_valid(write_concern)); mongoc_write_concern_destroy(write_concern); } static void test_write_concern_wtimeout_validity (void) { mongoc_write_concern_t *write_concern = mongoc_write_concern_new(); /* Test defaults */ ASSERT(write_concern); ASSERT(mongoc_write_concern_get_w(write_concern) == MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(mongoc_write_concern_get_wtimeout(write_concern) == 0); ASSERT(!mongoc_write_concern_get_wmajority(write_concern)); /* mongoc_write_concern_set_wtimeout() ignores invalid wtimeout */ mongoc_write_concern_set_wtimeout(write_concern, -1); ASSERT(mongoc_write_concern_get_w(write_concern) == MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(mongoc_write_concern_get_wtimeout(write_concern) == 0); ASSERT(!mongoc_write_concern_get_wmajority(write_concern)); ASSERT(_mongoc_write_concern_is_valid(write_concern)); /* mongoc_write_concern_set_wmajority() ignores invalid wtimeout */ mongoc_write_concern_set_wmajority(write_concern, -1); ASSERT(mongoc_write_concern_get_w(write_concern) == MONGOC_WRITE_CONCERN_W_MAJORITY); ASSERT(mongoc_write_concern_get_wtimeout(write_concern) == 0); ASSERT(mongoc_write_concern_get_wmajority(write_concern)); ASSERT(_mongoc_write_concern_is_valid(write_concern)); /* Manually assigning a negative wtimeout will make the write concern invalid */ write_concern->wtimeout = -1; ASSERT(!_mongoc_write_concern_is_valid(write_concern)); mongoc_write_concern_destroy(write_concern); } void test_write_concern_install (TestSuite *suite) { TestSuite_Add (suite, "/WriteConcern/basic", test_write_concern_basic); TestSuite_Add (suite, "/WriteConcern/bson_omits_defaults", test_write_concern_bson_omits_defaults); TestSuite_Add (suite, "/WriteConcern/bson_includes_false_fsync_and_journal", test_write_concern_bson_includes_false_fsync_and_journal); TestSuite_Add (suite, "/WriteConcern/fsync_and_journal_gle_and_validity", test_write_concern_fsync_and_journal_gle_and_validity); TestSuite_Add (suite, "/WriteConcern/wtimeout_validity", test_write_concern_wtimeout_validity); } libmongoc-1.3.1/tests/test-replica-set-ssl.c000066400000000000000000000055061264720626300207750ustar00rootroot00000000000000#include #include "ha-test.h" #include "mongoc-client-private.h" #include "mongoc-tests.h" #include "mongoc-write-concern-private.h" #include "TestSuite.h" #define TRUST_DIR "tests/trust_dir" #define CAFILE TRUST_DIR "/verify/mongo_root.pem" #define PEMFILE_LOCALHOST TRUST_DIR "/keys/127.0.0.1.pem" #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "test" static char * gTestCAFile; static char * gTestPEMFileLocalhost; static bool use_pool; static void test_replica_set_ssl_client(void) { mongoc_collection_t *collection; mongoc_client_t *client; mongoc_client_pool_t *pool = NULL; ha_replica_set_t *replica_set; bson_error_t error; bson_t b; mongoc_ssl_opt_t sopt = { 0 }; sopt.pem_file = gTestPEMFileLocalhost; sopt.ca_file = gTestCAFile; replica_set = ha_replica_set_new("repltest1"); ha_replica_set_ssl(replica_set, &sopt); ha_replica_set_add_replica(replica_set, "replica1"); ha_replica_set_add_replica(replica_set, "replica2"); ha_replica_set_add_replica(replica_set, "replica3"); ha_replica_set_start(replica_set); ha_replica_set_wait_for_healthy(replica_set); if (use_pool) { pool = ha_replica_set_create_client_pool(replica_set); client = mongoc_client_pool_pop (pool); } else { client = ha_replica_set_create_client(replica_set); } assert(client); collection = mongoc_client_get_collection(client, "test", "test"); assert(collection); bson_init(&b); bson_append_utf8(&b, "hello", -1, "world", -1); ASSERT_OR_PRINT (mongoc_collection_insert(collection, MONGOC_INSERT_NONE, &b, NULL, &error), error); mongoc_collection_destroy(collection); if (use_pool) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy(client); } bson_destroy(&b); ha_replica_set_shutdown(replica_set); ha_replica_set_destroy(replica_set); } static void log_handler (mongoc_log_level_t log_level, const char *domain, const char *message, void *user_data) { /* Do Nothing */ } int main (int argc, /* IN */ char *argv[]) /* IN */ { char *cwd; char buf[1024]; if (argc <= 1 || !!strcmp (argv[1], "-v")) { mongoc_log_set_handler (log_handler, NULL); } mongoc_init (); cwd = getcwd(buf, sizeof(buf)); assert(cwd); gTestCAFile = bson_strdup_printf("%s/" CAFILE, cwd); gTestPEMFileLocalhost = bson_strdup_printf("%s/" PEMFILE_LOCALHOST, cwd); use_pool = false; run_test("/ReplicaSet/single/ssl/client", &test_replica_set_ssl_client); use_pool = true; run_test("/ReplicaSet/pool/ssl/client", &test_replica_set_ssl_client); bson_free(gTestCAFile); bson_free(gTestPEMFileLocalhost); mongoc_cleanup(); return 0; } libmongoc-1.3.1/tests/test-replica-set.c000066400000000000000000000222051264720626300201710ustar00rootroot00000000000000#include "mongoc-tests.h" #include "ha-test.h" #include "mongoc-client-private.h" #include "mongoc-cursor-private.h" #include "mongoc-write-concern-private.h" #include "TestSuite.h" #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "test" static ha_replica_set_t *replica_set; static ha_node_t *r1; static ha_node_t *r2; static ha_node_t *r3; static ha_node_t *a1; static bool use_pool; static void insert_test_docs (mongoc_collection_t *collection) { mongoc_write_concern_t *write_concern; bson_error_t error; bson_oid_t oid; bson_t b; int i; write_concern = mongoc_write_concern_new(); mongoc_write_concern_set_w(write_concern, 3); { const bson_t *wc; char *str; wc = _mongoc_write_concern_get_gle(write_concern); str = bson_as_json(wc, NULL); fprintf(stderr, "Write Concern: %s\n", str); bson_free(str); } for (i = 0; i < 200; i++) { bson_init(&b); bson_oid_init(&oid, NULL); bson_append_oid(&b, "_id", 3, &oid); ASSERT_OR_PRINT (mongoc_collection_insert(collection, MONGOC_INSERT_NONE, &b, write_concern, &error), error); bson_destroy(&b); } mongoc_write_concern_destroy(write_concern); } static ha_node_t * get_replica (mongoc_client_t *client, uint32_t id) { mongoc_server_description_t *description; ha_node_t *iter; description = mongoc_topology_server_by_id(client->topology, id, NULL); BSON_ASSERT(description); for (iter = replica_set->nodes; iter; iter = iter->next) { if (iter->port == description->host.port) { mongoc_server_description_destroy(description); return iter; } } mongoc_server_description_destroy(description); BSON_ASSERT(false); return NULL; } /* *-------------------------------------------------------------------------- * * test1 -- * * Tests the failover scenario of a node having a network partition * between the time the client recieves the first OP_REPLY and the * submission of a followup OP_GETMORE. * * This function will abort() upon failure. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void test1 (void) { mongoc_server_description_t *description; mongoc_collection_t *collection; mongoc_read_prefs_t *read_prefs; mongoc_cursor_t *cursor; mongoc_client_t *client; mongoc_client_pool_t *pool = NULL; const bson_t *doc; bson_error_t error; bool r; ha_node_t *replica; bson_t q; int i; bson_init(&q); if (use_pool) { pool = ha_replica_set_create_client_pool(replica_set); client = mongoc_client_pool_pop (pool); } else { client = ha_replica_set_create_client(replica_set); } collection = mongoc_client_get_collection(client, "test1", "test1"); MONGOC_DEBUG("Inserting test documents."); insert_test_docs(collection); MONGOC_INFO("Test documents inserted."); read_prefs = mongoc_read_prefs_new(MONGOC_READ_SECONDARY); MONGOC_DEBUG("Sending query to a SECONDARY."); cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 100, &q, NULL, read_prefs); BSON_ASSERT(cursor); BSON_ASSERT(!cursor->hint); /* * Send OP_QUERY to server and get first document back. */ MONGOC_INFO("Sending OP_QUERY."); r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(r); BSON_ASSERT(cursor->hint); BSON_ASSERT(cursor->sent); BSON_ASSERT(!cursor->done); BSON_ASSERT(cursor->rpc.reply.n_returned == 100); BSON_ASSERT(!cursor->end_of_event); /* * Make sure we queried a secondary. */ description = mongoc_topology_server_by_id(client->topology, cursor->hint, &error); ASSERT_OR_PRINT (description, error); BSON_ASSERT (description->type != MONGOC_SERVER_RS_PRIMARY); mongoc_server_description_destroy(description); /* * Exhaust the items in our first OP_REPLY. */ MONGOC_DEBUG("Exhausting OP_REPLY."); for (i = 0; i < 98; i++) { r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(r); BSON_ASSERT(cursor->hint); BSON_ASSERT(!cursor->done); BSON_ASSERT(!cursor->end_of_event); } /* * Finish off the last item in this OP_REPLY. */ MONGOC_INFO("Fetcing last doc from OP_REPLY."); r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(r); BSON_ASSERT(cursor->hint); BSON_ASSERT(cursor->sent); BSON_ASSERT(!cursor->done); BSON_ASSERT(!cursor->end_of_event); /* * Determine which node we queried by using the hint to * get the cluster information. */ BSON_ASSERT(cursor->hint); replica = get_replica(client, cursor->hint); /* * Kill the node we are communicating with. */ MONGOC_INFO("Killing replicaSet node to synthesize failure."); ha_node_kill(replica); /* * Try to fetch the next result set, expect failure. */ MONGOC_DEBUG("Checking for expected failure."); r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(!r); r = mongoc_cursor_error(cursor, &error); BSON_ASSERT(r); MONGOC_WARNING("%s", error.message); mongoc_cursor_destroy(cursor); mongoc_read_prefs_destroy(read_prefs); mongoc_collection_destroy(collection); if (use_pool) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy(client); } bson_destroy(&q); ha_node_restart(replica); } static void test2 (void) { mongoc_read_prefs_t *read_prefs; mongoc_collection_t *collection; mongoc_cursor_t *cursor; mongoc_client_t *client; mongoc_client_pool_t *pool = NULL; const bson_t *doc; bson_error_t error; bool r; bson_t q; bson_init(&q); /* * Start by killing 2 of the replica set nodes. */ ha_node_kill(r1); ha_node_kill(r2); if (use_pool) { pool = ha_replica_set_create_client_pool(replica_set); client = mongoc_client_pool_pop (pool); } else { client = ha_replica_set_create_client(replica_set); } collection = mongoc_client_get_collection(client, "test2", "test2"); /* * Perform a query and ensure it fails with no nodes available. */ read_prefs = mongoc_read_prefs_new(MONGOC_READ_SECONDARY_PREFERRED); cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 100, 0, &q, NULL, read_prefs); /* * Try to submit OP_QUERY. Since it is SECONDARY PREFERRED, it should * succeed if there is any node up (which r3 is up). */ r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(!r); /* No docs */ /* No error, slaveOk was set */ ASSERT_OR_PRINT (!mongoc_cursor_error(cursor, &error), error); mongoc_read_prefs_destroy(read_prefs); mongoc_cursor_destroy(cursor); mongoc_collection_destroy(collection); if (use_pool) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy(client); } bson_destroy(&q); ha_node_restart(r1); ha_node_restart(r2); } /* *-------------------------------------------------------------------------- * * main -- * * Test various replica-set failure scenarios. * * Returns: * 0 on success; otherwise context specific error code. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int main (int argc, /* IN */ char *argv[]) /* IN */ { mongoc_init(); replica_set = ha_replica_set_new("repltest1"); r1 = ha_replica_set_add_replica(replica_set, "replica1"); r2 = ha_replica_set_add_replica(replica_set, "replica2"); r3 = ha_replica_set_add_replica(replica_set, "replica3"); a1 = ha_replica_set_add_arbiter(replica_set, "arbiter1"); ha_replica_set_start(replica_set); ha_replica_set_wait_for_healthy(replica_set); use_pool = false; run_test("/ReplicaSet/single/lose_node_during_cursor", test1); ha_replica_set_wait_for_healthy(replica_set); use_pool = true; run_test("/ReplicaSet/pool/lose_node_during_cursor", test1); ha_replica_set_wait_for_healthy(replica_set); use_pool = false; run_test("/ReplicaSet/single/cursor_with_2_of_3_replicas_down", test2); ha_replica_set_wait_for_healthy(replica_set); use_pool = true; run_test("/ReplicaSet/pool/cursor_with_2_of_3_replicas_down", test2); ha_replica_set_wait_for_healthy(replica_set); ha_replica_set_shutdown(replica_set); ha_replica_set_destroy(replica_set); mongoc_cleanup(); return 0; } libmongoc-1.3.1/tests/test-sasl.c000066400000000000000000000076421264720626300167330ustar00rootroot00000000000000/* * Copyright 2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "TestSuite.h" #include "test-libmongoc.h" static const char *GSSAPI_HOST = "MONGOC_TEST_GSSAPI_HOST"; static const char *GSSAPI_USER = "MONGOC_TEST_GSSAPI_USER"; #define NTHREADS 10 #define NLOOPS 10 int should_run_gssapi_kerberos (void) { char *host = test_framework_getenv (GSSAPI_HOST); char *user = test_framework_getenv (GSSAPI_USER); int ret = (host && user); bson_free (host); bson_free (user); return ret; } struct closure_t { mongoc_client_pool_t *pool; int finished; mongoc_mutex_t mutex; }; static void * gssapi_kerberos_worker (void *data) { struct closure_t *closure = (struct closure_t *)data; mongoc_client_pool_t *pool = closure->pool; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; bson_t query = BSON_INITIALIZER; int i; for (i = 0; i < NLOOPS; i++) { client = mongoc_client_pool_pop (pool); collection = mongoc_client_get_collection (client, "test", "collection"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, NULL, NULL); if (!mongoc_cursor_next (cursor, &doc) && mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Cursor Failure: %s\n", error.message); abort (); } mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_pool_push (pool, client); } bson_destroy (&query); mongoc_mutex_lock (&closure->mutex); closure->finished++; mongoc_mutex_unlock (&closure->mutex); return NULL; } static void test_gssapi_kerberos (void *context) { char *host = test_framework_getenv (GSSAPI_HOST); char *user = test_framework_getenv (GSSAPI_USER); char *uri_str; mongoc_uri_t *uri; struct closure_t closure = { 0 }; int i; mongoc_thread_t threads[NTHREADS]; assert (host && user); mongoc_mutex_init (&closure.mutex); uri_str = bson_strdup_printf ( "mongodb://%s@%s/?authMechanism=GSSAPI&serverselectiontimeoutms=1000", user, host); uri = mongoc_uri_new (uri_str); closure.pool = mongoc_client_pool_new (uri); for (i = 0; i < NTHREADS; i++) { mongoc_thread_create (&threads[i], gssapi_kerberos_worker, (void *)&closure); } for (i = 0; i < NTHREADS; i++) { mongoc_thread_join (threads[i]); } mongoc_mutex_lock (&closure.mutex); ASSERT_CMPINT (NTHREADS, ==, closure.finished); mongoc_mutex_unlock (&closure.mutex); mongoc_client_pool_destroy (closure.pool); mongoc_mutex_destroy (&closure.mutex); mongoc_uri_destroy (uri); bson_free (uri_str); bson_free (host); bson_free (user); } void test_sasl_install (TestSuite *suite) { TestSuite_AddFull (suite, "/SASL/gssapi_kerberos", test_gssapi_kerberos, NULL, NULL, should_run_gssapi_kerberos); } libmongoc-1.3.1/tests/test-secondary.c000066400000000000000000000041261264720626300177520ustar00rootroot00000000000000#include static bool gExpectingFailure; static bool gShutdown; static void query_collection (mongoc_collection_t *col) { mongoc_cursor_t *cursor; const bson_t *doc; bson_error_t error; bson_t q; mongoc_init (); bson_init(&q); bson_append_utf8(&q, "hello", -1, "world", -1); cursor = mongoc_collection_find(col, MONGOC_QUERY_NONE, 0, 0, 0, &q, NULL, NULL); while (mongoc_cursor_next(cursor, &doc)) { char *str; str = bson_as_json(doc, NULL); fprintf(stderr, "%s\n", str); bson_free(str); } if (mongoc_cursor_error(cursor, &error)) { if (gExpectingFailure) { if ((error.domain != MONGOC_ERROR_STREAM) || (error.code != MONGOC_ERROR_STREAM_SOCKET)) { abort(); } gExpectingFailure = false; } else { fprintf (stderr, "%s", error.message); abort(); } } bson_destroy(&q); } static void test_secondary (mongoc_client_t *client) { mongoc_collection_t *col; col = mongoc_client_get_collection(client, "test", "test"); while (!gShutdown) { query_collection(col); } mongoc_collection_destroy(col); } int main (int argc, char *argv[]) { mongoc_read_prefs_t *read_prefs; mongoc_client_t *client; mongoc_uri_t *uri; if (argc < 2) { fprintf(stderr, "usage: %s mongodb://...\n", argv[0]); return EXIT_FAILURE; } uri = mongoc_uri_new(argv[1]); if (!uri) { fprintf(stderr, "Invalid URI: \"%s\"\n", argv[1]); return EXIT_FAILURE; } client = mongoc_client_new_from_uri(uri); read_prefs = mongoc_read_prefs_new(MONGOC_READ_SECONDARY); mongoc_client_set_read_prefs(client, read_prefs); mongoc_read_prefs_destroy(read_prefs); test_secondary(client); mongoc_client_destroy(client); mongoc_uri_destroy(uri); return EXIT_SUCCESS; } libmongoc-1.3.1/tests/test-sharded-cluster.c000066400000000000000000000043421264720626300210540ustar00rootroot00000000000000#include "mongoc-tests.h" #include #include "ha-test.h" static ha_sharded_cluster_t *cluster; static ha_replica_set_t *repl_1; static ha_replica_set_t *repl_2; static ha_node_t *node_1_1; static ha_node_t *node_1_2; static ha_node_t *node_1_3; static ha_node_t *node_2_1; static ha_node_t *node_2_2; static ha_node_t *node_2_3; static void test1 (void) { mongoc_collection_t *collection; mongoc_client_t *client; bson_error_t error = { 0 }; bool r; bson_t q = BSON_INITIALIZER; int i; BSON_ASSERT (cluster); bson_append_utf8 (&q, "hello", -1, "world", -1); client = ha_sharded_cluster_get_client (cluster); collection = mongoc_client_get_collection (client, "test", "test"); for (i = 0; i < 100; i++) { r = mongoc_collection_insert (collection, MONGOC_INSERT_NONE, &q, NULL, &error); BSON_ASSERT (r); BSON_ASSERT (!error.domain); BSON_ASSERT (!error.code); } mongoc_collection_destroy (collection); mongoc_client_destroy (client); bson_destroy (&q); } int main (int argc, char *argv[]) { mongoc_init(); repl_1 = ha_replica_set_new("shardtest1"); node_1_1 = ha_replica_set_add_replica(repl_1, "shardtest1_1"); node_1_2 = ha_replica_set_add_replica(repl_1, "shardtest1_2"); node_1_3 = ha_replica_set_add_replica(repl_1, "shardtest1_3"); repl_2 = ha_replica_set_new("shardtest2"); node_2_1 = ha_replica_set_add_replica(repl_2, "shardtest2_1"); node_2_2 = ha_replica_set_add_replica(repl_2, "shardtest2_2"); node_2_3 = ha_replica_set_add_replica(repl_2, "shardtest2_3"); cluster = ha_sharded_cluster_new("cluster1"); ha_sharded_cluster_add_replica_set(cluster, repl_1); ha_sharded_cluster_add_replica_set(cluster, repl_2); ha_sharded_cluster_add_config(cluster, "config1"); ha_sharded_cluster_add_router(cluster, "router1"); ha_sharded_cluster_add_router(cluster, "router2"); ha_sharded_cluster_start(cluster); ha_sharded_cluster_wait_for_healthy(cluster); run_test("/ShardedCluster/basic", test1); ha_sharded_cluster_shutdown(cluster); mongoc_cleanup(); return 0; } libmongoc-1.3.1/tests/test-write-commands.c000066400000000000000000000177771264720626300207340ustar00rootroot00000000000000#include #include #include "mongoc-client-private.h" #include "mongoc-collection-private.h" #include "mongoc-write-command-private.h" #include "mongoc-write-concern-private.h" #include "TestSuite.h" #include "test-libmongoc.h" #include "mongoc-tests.h" #include "test-conveniences.h" static mongoc_collection_t * get_test_collection (mongoc_client_t *client, const char *prefix) { mongoc_collection_t *ret; char *str; str = gen_collection_name (prefix); ret = mongoc_client_get_collection (client, "test", str); bson_free (str); return ret; } static void test_split_insert (void) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_command_t command; mongoc_write_result_t result; mongoc_collection_t *collection; mongoc_client_t *client; bson_oid_t oid; bson_t **docs; bson_t reply = BSON_INITIALIZER; bson_error_t error; mongoc_server_stream_t *server_stream; int i; client = test_framework_client_new (); assert (client); collection = get_test_collection (client, "test_split_insert"); assert (collection); docs = (bson_t **)bson_malloc (sizeof(bson_t*) * 3000); for (i = 0; i < 3000; i++) { docs [i] = bson_new (); bson_oid_init (&oid, NULL); BSON_APPEND_OID (docs [i], "_id", &oid); } _mongoc_write_result_init (&result); _mongoc_write_command_init_insert (&command, docs[0], write_flags, true); for (i = 1; i < 3000; i++) { _mongoc_write_command_insert_append (&command, docs[i]); } server_stream = mongoc_cluster_stream_for_writes (&client->cluster, &error); ASSERT_OR_PRINT (server_stream, error); _mongoc_write_command_execute (&command, client, server_stream, collection->db, collection->collection, NULL, 0, &result); ASSERT_OR_PRINT (_mongoc_write_result_complete (&result, &reply, &error), error); assert (result.nInserted == 3000); _mongoc_write_command_destroy (&command); _mongoc_write_result_destroy (&result); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); for (i = 0; i < 3000; i++) { bson_destroy (docs [i]); } bson_free (docs); mongoc_server_stream_cleanup (server_stream); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } static void test_invalid_write_concern (void) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_command_t command; mongoc_write_result_t result; mongoc_collection_t *collection; mongoc_client_t *client; mongoc_write_concern_t *write_concern; mongoc_server_stream_t *server_stream; bson_t *doc; bson_t reply = BSON_INITIALIZER; bson_error_t error; bool r; client = test_framework_client_new (); assert(client); collection = get_test_collection(client, "test_invalid_write_concern"); assert(collection); write_concern = mongoc_write_concern_new(); assert(write_concern); mongoc_write_concern_set_w(write_concern, 0); mongoc_write_concern_set_journal(write_concern, true); assert(!_mongoc_write_concern_is_valid(write_concern)); doc = BCON_NEW("_id", BCON_INT32(0)); _mongoc_write_command_init_insert(&command, doc, write_flags, true); _mongoc_write_result_init (&result); server_stream = mongoc_cluster_stream_for_writes (&client->cluster, &error); ASSERT_OR_PRINT (server_stream, error); _mongoc_write_command_execute (&command, client, server_stream, collection->db, collection->collection, write_concern, 0, &result); r = _mongoc_write_result_complete (&result, &reply, &error); assert(!r); ASSERT_CMPINT(error.domain, ==, MONGOC_ERROR_COMMAND); ASSERT_CMPINT(error.code, ==, MONGOC_ERROR_COMMAND_INVALID_ARG); _mongoc_write_command_destroy (&command); _mongoc_write_result_destroy (&result); bson_destroy(doc); mongoc_server_stream_cleanup (server_stream); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mongoc_write_concern_destroy(write_concern); } static void test_bypass_validation (void *context) { mongoc_collection_t *collection; bson_t reply = BSON_INITIALIZER; mongoc_bulk_operation_t *bulk; mongoc_database_t *database; mongoc_write_concern_t *wr; mongoc_client_t *client; bson_error_t error; bson_t *options; char *collname; char *dbname; int r; int i; client = test_framework_client_new (); assert (client); dbname = gen_collection_name ("dbtest"); collname = gen_collection_name ("bypass"); database = mongoc_client_get_database (client, dbname); collection = mongoc_database_get_collection (database, collname); assert (collection); options = tmp_bson ("{'validator': {'number': {'$gte': 5}}, 'validationAction': 'error'}"); ASSERT_OR_PRINT (mongoc_database_create_collection (database, collname, options, &error), error); /* {{{ Default fails validation */ bulk = mongoc_collection_create_bulk_operation(collection, true, NULL); for (i = 0; i < 3; i++) { bson_t *doc = tmp_bson (bson_strdup_printf ("{'number': 3, 'high': %d }", i)); mongoc_bulk_operation_insert (bulk, doc); } r = mongoc_bulk_operation_execute (bulk, &reply, &error); ASSERT(!r); ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, 121, "Document failed validation"); mongoc_bulk_operation_destroy (bulk); /* }}} */ /* {{{ bypass_document_validation=false Fails validation */ bulk = mongoc_collection_create_bulk_operation(collection, true, NULL); mongoc_bulk_operation_set_bypass_document_validation (bulk, false); for (i = 0; i < 3; i++) { bson_t *doc = tmp_bson (bson_strdup_printf ("{'number': 3, 'high': %d }", i)); mongoc_bulk_operation_insert (bulk, doc); } r = mongoc_bulk_operation_execute (bulk, &reply, &error); ASSERT(!r); ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, 121, "Document failed validation"); mongoc_bulk_operation_destroy (bulk); /* }}} */ /* {{{ bypass_document_validation=true ignores validation */ bulk = mongoc_collection_create_bulk_operation(collection, true, NULL); mongoc_bulk_operation_set_bypass_document_validation (bulk, true); for (i = 0; i < 3; i++) { bson_t *doc = tmp_bson (bson_strdup_printf ("{'number': 3, 'high': %d }", i)); mongoc_bulk_operation_insert (bulk, doc); } r = mongoc_bulk_operation_execute (bulk, &reply, &error); ASSERT_OR_PRINT(r, error); mongoc_bulk_operation_destroy (bulk); /* }}} */ /* {{{ w=0 and bypass_document_validation=set fails */ bulk = mongoc_collection_create_bulk_operation(collection, true, NULL); wr = mongoc_write_concern_new (); mongoc_write_concern_set_w (wr, 0); mongoc_bulk_operation_set_write_concern (bulk, wr); mongoc_bulk_operation_set_bypass_document_validation (bulk, true); for (i = 0; i < 3; i++) { bson_t *doc = tmp_bson (bson_strdup_printf ("{'number': 3, 'high': %d }", i)); mongoc_bulk_operation_insert (bulk, doc); } r = mongoc_bulk_operation_execute (bulk, &reply, &error); ASSERT_OR_PRINT(!r, error); ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set bypassDocumentValidation for unacknowledged writes"); mongoc_bulk_operation_destroy (bulk); mongoc_write_concern_destroy (wr); /* }}} */ ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); mongoc_collection_destroy (collection); mongoc_client_destroy (client); } void test_write_command_install (TestSuite *suite) { TestSuite_Add (suite, "/WriteCommand/split_insert", test_split_insert); TestSuite_Add (suite, "/WriteCommand/invalid_write_concern", test_invalid_write_concern); TestSuite_AddFull (suite, "/WriteCommand/bypass_validation", test_bypass_validation, NULL, NULL, test_framework_skip_if_max_version_version_less_than_4); } libmongoc-1.3.1/tests/test-x509.c000066400000000000000000000007301264720626300164650ustar00rootroot00000000000000#include #include #include "TestSuite.h" static void test_extract_subject (void) { char *subject; subject = _mongoc_ssl_extract_subject (BINARY_DIR"/../certificates/client.pem"); ASSERT (0 == strcmp (subject, "CN=client,OU=kerneluser,O=10Gen,L=New York City,ST=New York,C=US")); bson_free (subject); } void test_x509_install (TestSuite *suite) { TestSuite_Add (suite, "/SSL/extract_subject", test_extract_subject); } libmongoc-1.3.1/tests/trust_dir.cnf000066400000000000000000000037261264720626300173560ustar00rootroot00000000000000[ ca ] default_ca = CA_default [ CA_default ] dir = tests/trust_dir certificate = $dir/signing-ca.crt cert_opt = ca_default certs = $dir/ca.db.certs crl_dir = $dir/crl database = $dir/ca.db.index default_crl_days = 30 default_days = 365 default_md = sha1 name_opt = ca_default new_certs_dir = $dir/ca.db.certs policy = policy_match preserve = no private_key = $dir/signing-ca.key RANDFILE = $dir/ca.db.rand serial = $dir/ca.db.serial unique_subject = yes x509_extensions = usr_cert [ policy_match ] commonName = supplied countryName = match emailAddress = optional localityName = match organizationalUnitName = optional organizationName = match stateOrProvinceName = match [ policy_anything ] commonName = supplied countryName = optional emailAddress = optional localityName = optional organizationalUnitName = optional organizationName = optional stateOrProvinceName = optional [ req ] attributes = req_attributes default_bits = 4096 default_keyfile = privkey.pem distinguished_name = req_distinguished_name req_extensions = v3_req string_mask = nombstr x509_extensions = v3_ca [ req_distinguished_name ] [ req_attributes ] [ usr_cert ] authorityKeyIdentifier = keyid,issuer:always basicConstraints = CA:FALSE nsComment = "OpenSSL Generated Certificate" subjectKeyIdentifier = hash [ v3_req ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [ alt_names ] DNS.1 = alt2.mongodb.com DNS.2 = *.wild.mongodb.com IP.1 = 192.168.1.1 IP.2 = 10.0.0.1 [ v3_ca ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:always basicConstraints = CA:true [ crl_ext ] authorityKeyIdentifier = keyid:always,issuer:always libmongoc-1.3.1/valgrind.suppressions000066400000000000000000000016611264720626300200060ustar00rootroot00000000000000{ ignore_libcrypto_conditional_jump_errors_in_leak Memcheck:Leak ... obj:*/libcrypto.so.* } { ignore_libcrypto_conditional_jump_errors_in_cond Memcheck:Cond ... obj:*/libcrypto.so.* } { ignore_libssl_conditional_jump_errors_in_cond Memcheck:Cond ... obj:*/libssl.so.* } { ignore_libcrypto_conditional_jump_errors_in_value8 Memcheck:Value8 ... obj:*/libcrypto.so.* } { ignore_scram_nonce_uninitialized_warning_cond Memcheck:Cond fun:mongoc_b64_ntop ... fun:_mongoc_scram_step ... } { ignore_scram_nonce_uninitialized_warning_value8 Memcheck:Value8 fun:mongoc_b64_ntop ... fun:_mongoc_scram_step ... } { ignore_libcrypto_conditional_jump_errors_in_param Memcheck:Param sendmsg(msg.msg_iov[0]) ... obj:*/libcrypto.so.* } { ignore_sasl_load_plugin_reachable_warnings Memcheck:Leak ... fun:_sasl_get_plugin ... fun:_mongoc_do_init }