diff --git a/CMakeLists.txt b/CMakeLists.txt
index fff7808e1..3541353d5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,12 +1,78 @@
-# CMake build script for libzerotiercore.a
+# CMake build script for ZeroTier One
cmake_minimum_required (VERSION 2.8)
-project (zerotiercore)
+project (zerotier-one)
-set (PROJ_DIR ${PROJECT_SOURCE_DIR})
-set (ZT_DEFS -std=c++11)
+option(BUILD_CENTRAL_CONTROLLER "Build ZeroTier Central Controller" OFF)
-file(GLOB core_src_glob ${PROJ_DIR}/node/*.cpp)
-add_library(zerotiercore STATIC ${core_src_glob})
+if (BUILD_CENTRAL_CONTROLLER)
+ find_package(PostgreSQL REQUIRED)
-target_compile_options(zerotiercore PRIVATE ${ZT_DEFS})
+ set(ENABLE_SSL_SUPPORT OFF)
+ set(BUILD_SHARED_LIBS OFF)
+ set(BUILD_EXAMPLES OFF)
+ set(BUILD_TOOLS OFF)
+ set(BUILD_TESTS OFF)
+ set(BUILD_API_DOCS OFF)
+ add_subdirectory("ext/librabbitmq")
+endif(BUILD_CENTRAL_CONTROLLER)
+
+if(CMAKE_BUILD_TYPE EQUAL "Debug")
+ add_definitions(-DZT_TRACE)
+endif(CMAKE_BUILD_TYPE EQUAL "Debug")
+
+if(WIN32)
+ add_definitions(-DNOMINMAX)
+ if(CMAKE_BUILD_TYPE EQUAL "Debug")
+ add_definitions(-DZT_WIN_RUN_IN_CONSOLE)
+ endif(CMAKE_BUILD_TYPE EQUAL "Debug")
+endif(WIN32)
+
+
+add_subdirectory(node)
+add_subdirectory(controller)
+add_subdirectory(osdep)
+add_subdirectory(service)
+
+if(WIN32)
+ add_definitions(-DNOMINMAX)
+endif(WIN32)
+
+set(libs
+ zt_controller
+ zt_core
+ zt_osdep
+ zt_service
+)
+
+set(src
+ one.cpp
+ "ext/http-parser/http_parser.c"
+)
+set(headers
+ "ext/http-parser/http_parser.h"
+)
+
+if(WIN32)
+ set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi)
+ set(src
+ ${src}
+ "windows/ZeroTierOne/ServiceBase.cpp"
+ "windows/ZeroTierOne/ServiceInstaller.cpp"
+ "windows/ZeroTierOne/ZeroTierOneService.cpp"
+ "windows/ZeroTierOne/ZeroTierOne.rc"
+ )
+ set(headers
+ ${headers}
+ "windows/ZeroTierOne/ServiceBase.h"
+ "windows/ZeroTierOne/ServiceInstaller.h"
+ "windows/ZeroTierOne/ZeroTierOneService.h"
+ )
+endif(WIN32)
+
+if(BUILD_CENTRAL_CONTROLLER)
+ set(libs ${libs} rabbitmq-static ${PostgreSQL_LIBRARIES})
+endif(BUILD_CENTRAL_CONTROLLER)
+
+add_executable(${PROJECT_NAME} ${src} ${headers})
+target_link_libraries(${PROJECT_NAME} ${libs})
\ No newline at end of file
diff --git a/controller/CMakeLists.txt b/controller/CMakeLists.txt
new file mode 100644
index 000000000..25eb0dc7d
--- /dev/null
+++ b/controller/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 2.8)
+project(zt_controller)
+
+if(WIN32)
+ add_definitions(-DNOMINMAX)
+ if(CMAKE_BUILD_TYPE EQUAL "Debug")
+
+ endif(CMAKE_BUILD_TYPE EQUAL "Debug")
+endif(WIN32)
+
+set(ctl_src
+ DB.cpp
+ EmbeddedNetworkController.cpp
+ FileDB.cpp
+ RabbitMQ.cpp
+)
+
+set(ctl_hdr
+ DB.hpp
+ EmbeddedNetworkController.hpp
+ FileDB.hpp
+ RabbitMQ.hpp
+)
+
+if(BUILD_CENTRAL_CONTROLLER)
+ add_definitions(-DZT_CONTROLLER_USE_LIBPQ)
+ include_directories("../ext/librabbitmq/librabbitmq" ${PostgreSQL_INCLUDE_DIRS})
+
+ set(ctl_src ${ctl_src} PostgreSQL.cpp)
+ set(ctl_hdr ${ctl_hdr} PostgreSQL.hpp)
+endif(BUILD_CENTRAL_CONTROLLER)
+
+add_library(${PROJECT_NAME} STATIC ${ctl_src} ${ctl_hdr})
\ No newline at end of file
diff --git a/ext/librabbitmq/.clang-format b/ext/librabbitmq/.clang-format
new file mode 100644
index 000000000..8aa6b1a85
--- /dev/null
+++ b/ext/librabbitmq/.clang-format
@@ -0,0 +1,47 @@
+---
+# BasedOnStyle: Google
+AccessModifierOffset: -1
+ConstructorInitializerIndentWidth: 4
+AlignEscapedNewlinesLeft: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakTemplateDeclarations: true
+AlwaysBreakBeforeMultilineStrings: true
+BreakBeforeBinaryOperators: false
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BinPackParameters: true
+ColumnLimit: 80
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+DerivePointerBinding: true
+ExperimentalAutoDetectBinPacking: false
+IndentCaseLabels: true
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 60
+PenaltyBreakString: 1000
+PenaltyBreakFirstLessLess: 120
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerBindsToType: true
+SpacesBeforeTrailingComments: 2
+Cpp11BracedListStyle: true
+Standard: Auto
+IndentWidth: 2
+TabWidth: 8
+UseTab: Never
+BreakBeforeBraces: Attach
+IndentFunctionDeclarationAfterType: true
+SpacesInParentheses: false
+SpacesInAngles: false
+SpaceInEmptyParentheses: false
+SpacesInCStyleCastParentheses: false
+SpaceAfterControlStatementKeyword: true
+SpaceBeforeAssignmentOperators: true
+ContinuationIndentWidth: 4
+...
+
diff --git a/ext/librabbitmq/.gitattributes b/ext/librabbitmq/.gitattributes
new file mode 100644
index 000000000..a465161db
--- /dev/null
+++ b/ext/librabbitmq/.gitattributes
@@ -0,0 +1,18 @@
+# Default for those who don't have core.autocrlf set
+* text=auto
+
+# Things that should be treated like text (lines converted on checkout):
+*.c text
+*.h text
+*.py text
+*.cmake text
+*.md text
+# This is for the output of table_test
+*.expected text
+*.xml
+
+# Exceptions to the rule:
+*.ac text eol=lf
+*.am text eol=lf
+*.m4 text eol=lf
+
diff --git a/ext/librabbitmq/.gitignore b/ext/librabbitmq/.gitignore
new file mode 100644
index 000000000..1791e2800
--- /dev/null
+++ b/ext/librabbitmq/.gitignore
@@ -0,0 +1,73 @@
+*.la
+*.lo
+*.o
+.deps
+.dirstamp
+.libs
+/aclocal.m4
+/autom4te.cache
+/bin*
+/build
+/compile
+/config.guess
+/config.h
+/config.h.in
+/config.h.in~
+/config.log
+/config.status
+/config.sub
+/configure
+/cscope.*
+/depcomp
+/install-sh
+/libtool
+/ltmain.sh
+/missing
+/stamp-h1
+/test-suite.log
+INSTALL
+Makefile
+Makefile.in
+examples/amqp_bind
+examples/amqp_connect_timeout
+examples/amqp_consumer
+examples/amqp_exchange_declare
+examples/amqp_listen
+examples/amqp_listenq
+examples/amqp_producer
+examples/amqp_rpc_sendstring_client
+examples/amqp_sendstring
+examples/amqp_unbind
+examples/amqps_bind
+examples/amqps_connect_timeout
+examples/amqps_consumer
+examples/amqps_exchange_declare
+examples/amqps_listen
+examples/amqps_listenq
+examples/amqps_producer
+examples/amqps_sendstring
+examples/amqps_unbind
+librabbitmq.pc
+test-driver
+tests/*.log
+tests/*.trs
+tests/test_hostcheck
+tests/test_parse_url
+tests/test_status_enum
+tests/test_tables
+tools/amqp-consume
+tools/amqp-declare-queue
+tools/amqp-delete-queue
+tools/amqp-get
+tools/amqp-publish
+tools/doc/*.1
+tools/doc/*.7
+tools/doc/man-date.ent
+.ycm_extra_conf.py?
+.DS_Store
+
+# Ignore editor swap files
+*~
+*.sw?
+.#*
+\#*#
diff --git a/ext/librabbitmq/.gitmodules b/ext/librabbitmq/.gitmodules
new file mode 100644
index 000000000..b7f37f732
--- /dev/null
+++ b/ext/librabbitmq/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "codegen"]
+ path = codegen
+ url = https://github.com/rabbitmq/rabbitmq-codegen.git
+[submodule "travis/run-clang-format"]
+ path = travis/run-clang-format
+ url = https://github.com/Sarcasm/run-clang-format.git
diff --git a/ext/librabbitmq/.travis.yml b/ext/librabbitmq/.travis.yml
new file mode 100644
index 000000000..5d26e0f27
--- /dev/null
+++ b/ext/librabbitmq/.travis.yml
@@ -0,0 +1,92 @@
+# Travis-CI Build for rabbitmq-c
+# see travis-ci.org for details
+
+language: c
+
+dist: trusty
+# Currently libpopt-dev is not on the list of whitelisted apt-packages.
+sudo: true
+
+env:
+ global:
+ # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
+ # via the "travis encrypt" command using the project repo's public key
+ - secure: "gDwqo3jHj+HHGzFKnxL/nwZhbVeh2pItw0TbeaHcLtWubUZaf85ViEQRaXPyfnbG7l0OEQq+PjyhKAfvViVq2NP0lGeeu4VM5uMZJhsCLN594BJr39Y4XzOapg0O8mEMhQ0DU2u1Zo4LMgEcRz67aosVQOj6QV30tOzp9fnxn9U="
+
+services:
+ - rabbitmq
+
+matrix:
+ include:
+ # Note that the first compiler in the matrix must be gcc, so that the
+ # coverity_scan branch hack below works correctly.
+ - compiler: gcc
+ os: linux
+ env: CONFIG=cmake
+ - compiler: gcc
+ os: linux
+ env: CONFIG=format
+ - compiler: gcc
+ os: linux
+ env: CONFIG=coverage
+ - compiler: clang
+ os: linux
+ env: CONFIG=cmake
+ - compiler: clang
+ os: linux
+ env: CONFIG=asan
+ - compiler: clang
+ os: linux
+ env: CONFIG=tsan
+ - compiler: clang
+ os: linux
+ env: CONFIG=scan-build
+ - compiler: clang
+ os: osx
+ env: CONFIG=cmake
+ - compiler: gcc
+ os: linux
+ env: NAME="openssl-1.1.0" CONFIG=cmake
+ addons:
+ apt:
+ sources:
+ - sourceline: 'ppa:ondrej/nginx-mainline'
+ packages:
+ - libssl1.1
+ - openssl
+ - libssl-dev
+
+ allow_failures:
+ - compiler: clang
+ os: linux
+ env: CONFIG=tsan
+
+before_install:
+ - |
+ if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
+ wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
+ sudo apt-add-repository "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main"
+ sudo apt-get -q update;
+ sudo apt-get install -y clang-3.9 clang-format-3.9 libpopt-dev;
+ fi
+ # ugly hack; if running a coverity scan abort all except the 1st build
+ # see note re gcc compiler above needing to be 1st
+ # also note that branch_pattern & the TRAVIS_BRANCH check must match
+ # unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
+ # build process
+ - if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
+
+
+script:
+ # Don't bother building if this is being done in the coverity_scan branch.
+ - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./travis.sh $CONFIG ; fi
+
+addons:
+ coverity_scan:
+ project:
+ name: "alanxz/rabbitmq-c"
+ description: "C AMQP client for RabbitMQ"
+ notification_email: alan.antonuk@gmail.com
+ build_command_prepend: mkdir build && pushd build && cmake .. && popd
+ build_command: cmake --build ./build
+ branch_pattern: coverity_scan
diff --git a/ext/librabbitmq/.ycm_extra_conf.py b/ext/librabbitmq/.ycm_extra_conf.py
new file mode 100644
index 000000000..d9ef11c65
--- /dev/null
+++ b/ext/librabbitmq/.ycm_extra_conf.py
@@ -0,0 +1,157 @@
+# This file is NOT licensed under the GPLv3, which is the license for the rest
+# of YouCompleteMe.
+#
+# Here's the license text for this file:
+#
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+#
+# In jurisdictions that recognize copyright laws, the author or authors
+# of this software dedicate any and all copyright interest in the
+# software to the public domain. We make this dedication for the benefit
+# of the public at large and to the detriment of our heirs and
+# successors. We intend this dedication to be an overt act of
+# relinquishment in perpetuity of all present and future rights to this
+# software under copyright law.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# For more information, please refer to
+
+import os
+import ycm_core
+
+# These are the compilation flags that will be used in case there's no
+# compilation database set (by default, one is not set).
+# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
+flags = [
+'-Wall',
+'-Wextra',
+# THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which
+# language to use when compiling headers. So it will guess. Badly. So C++
+# headers will be compiled as C headers. You don't want that so ALWAYS specify
+# a "-std=".
+# For a C project, you would set this to something like 'c99' instead of
+# 'c++11'.
+'-std=gnu90',
+# ...and the same thing goes for the magic -x option which specifies the
+# language that the files to be compiled are written in. This is mostly
+# relevant for c++ headers.
+# For a C project, you would set this to 'c' instead of 'c++'.
+'-x',
+'c',
+'-I', './librabbitmq',
+'-I', './librabbitmq/unix',
+'-D', 'HAVE_POLL',
+]
+
+
+# Set this to the absolute path to the folder (NOT the file!) containing the
+# compile_commands.json file to use that instead of 'flags'. See here for
+# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
+#
+# You can get CMake to generate this file for you by adding:
+# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
+# to your CMakeLists.txt file.
+#
+# Most projects will NOT need to set this to anything; you can just change the
+# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
+compilation_database_folder = ''
+
+if os.path.exists( compilation_database_folder ):
+ database = ycm_core.CompilationDatabase( compilation_database_folder )
+else:
+ database = None
+
+SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
+
+def DirectoryOfThisScript():
+ return os.path.dirname( os.path.abspath( __file__ ) )
+
+
+def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
+ if not working_directory:
+ return list( flags )
+ new_flags = []
+ make_next_absolute = False
+ path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
+ for flag in flags:
+ new_flag = flag
+
+ if make_next_absolute:
+ make_next_absolute = False
+ if not flag.startswith( '/' ):
+ new_flag = os.path.join( working_directory, flag )
+
+ for path_flag in path_flags:
+ if flag == path_flag:
+ make_next_absolute = True
+ break
+
+ if flag.startswith( path_flag ):
+ path = flag[ len( path_flag ): ]
+ new_flag = path_flag + os.path.join( working_directory, path )
+ break
+
+ if new_flag:
+ new_flags.append( new_flag )
+ return new_flags
+
+
+def IsHeaderFile( filename ):
+ extension = os.path.splitext( filename )[ 1 ]
+ return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
+
+
+def GetCompilationInfoForFile( filename ):
+ # The compilation_commands.json file generated by CMake does not have entries
+ # for header files. So we do our best by asking the db for flags for a
+ # corresponding source file, if any. If one exists, the flags for that file
+ # should be good enough.
+ if IsHeaderFile( filename ):
+ basename = os.path.splitext( filename )[ 0 ]
+ for extension in SOURCE_EXTENSIONS:
+ replacement_file = basename + extension
+ if os.path.exists( replacement_file ):
+ compilation_info = database.GetCompilationInfoForFile(
+ replacement_file )
+ if compilation_info.compiler_flags_:
+ return compilation_info
+ return None
+ return database.GetCompilationInfoForFile( filename )
+
+
+def FlagsForFile( filename, **kwargs ):
+ if database:
+ # Bear in mind that compilation_info.compiler_flags_ does NOT return a
+ # python list, but a "list-like" StringVec object
+ compilation_info = GetCompilationInfoForFile( filename )
+ if not compilation_info:
+ relative_to = DirectoryOfThisScript()
+ return {
+ 'flags': MakeRelativePathsInFlagsAbsolute( flags, relative_to ),
+ 'do_cache': True
+ }
+
+ final_flags = MakeRelativePathsInFlagsAbsolute(
+ compilation_info.compiler_flags_,
+ compilation_info.compiler_working_dir_ )
+
+ else:
+ relative_to = DirectoryOfThisScript()
+ final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
+
+ return {
+ 'flags': final_flags,
+ 'do_cache': True
+ }
diff --git a/ext/librabbitmq/AUTHORS b/ext/librabbitmq/AUTHORS
new file mode 100644
index 000000000..bd0070cfc
--- /dev/null
+++ b/ext/librabbitmq/AUTHORS
@@ -0,0 +1,2 @@
+Tony Garnock-Jones
+The RabbitMQ team
diff --git a/ext/librabbitmq/CMakeLists.txt b/ext/librabbitmq/CMakeLists.txt
new file mode 100644
index 000000000..b5a931141
--- /dev/null
+++ b/ext/librabbitmq/CMakeLists.txt
@@ -0,0 +1,343 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(rabbitmq-c "C")
+
+# Enable MACOSX_RPATH by default. See: cmake --help-policy CMP0042
+if (POLICY CMP0042)
+ cmake_policy(SET CMP0042 NEW)
+endif()
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+
+# Follow all steps below in order to calculate new ABI version when updating the library
+# NOTE: THIS IS UNRELATED to the actual project version
+#
+# 1. If the library source code has changed at all since the last update, then increment revision
+# 2. If any interfaces have been added, removed, or changed since the last update, increment current and set revision to 0.
+# 3. If any interfaces have been added since the last public release, then increment age.
+# 4. If any interfaces have been removed since the last public release, then set age to 0.
+
+set(RMQ_SOVERSION_CURRENT 7)
+set(RMQ_SOVERSION_REVISION 0)
+set(RMQ_SOVERSION_AGE 3)
+
+math(EXPR RMQ_SOVERSION_MAJOR "${RMQ_SOVERSION_CURRENT} - ${RMQ_SOVERSION_AGE}")
+math(EXPR RMQ_SOVERSION_MINOR "${RMQ_SOVERSION_AGE}")
+math(EXPR RMQ_SOVERSION_PATCH "${RMQ_SOVERSION_REVISION}")
+
+set(RMQ_VERSION ${RMQ_SOVERSION_MAJOR}.${RMQ_SOVERSION_MINOR}.${RMQ_SOVERSION_PATCH})
+set(RMQ_SOVERSION ${RMQ_SOVERSION_MAJOR})
+
+file(STRINGS librabbitmq/amqp.h _API_VERSION_MAJOR REGEX "^#define AMQP_VERSION_MAJOR [0-9]+$")
+file(STRINGS librabbitmq/amqp.h _API_VERSION_MINOR REGEX "^#define AMQP_VERSION_MINOR [0-9]+$")
+file(STRINGS librabbitmq/amqp.h _API_VERSION_PATCH REGEX "^#define AMQP_VERSION_PATCH [0-9]+$")
+
+string(REGEX MATCH "[0-9]+" _API_VERSION_MAJOR ${_API_VERSION_MAJOR})
+string(REGEX MATCH "[0-9]+" _API_VERSION_MINOR ${_API_VERSION_MINOR})
+string(REGEX MATCH "[0-9]+" _API_VERSION_PATCH ${_API_VERSION_PATCH})
+
+# VERSION to match what is in autotools
+set(VERSION ${_API_VERSION_MAJOR}.${_API_VERSION_MINOR}.${_API_VERSION_PATCH})
+
+if (CMAKE_GENERATOR MATCHES ".*(Make|Ninja).*"
+ AND NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
+ message(STATUS "CMAKE_BUILD_TYPE not specified. Creating ${CMAKE_BUILD_TYPE} build")
+endif()
+
+include(TestCInline)
+include(CheckSymbolExists)
+include(CheckLibraryExists)
+include(CMakePushCheckState)
+include(GNUInstallDirs)
+include(CheckCCompilerFlag)
+
+# Detect if we need to link against a socket library:
+cmake_push_check_state()
+if (WIN32)
+ # Always use WinSock2 on Windows
+ set(SOCKET_LIBRARIES ws2_32)
+else ()
+ # Is it in the default link?
+ check_symbol_exists(getaddrinfo "sys/types.h;sys/socket.h;netdb.h" HAVE_GETADDRINFO)
+ if (NOT (HAVE_GETADDRINFO EQUAL 1))
+ SET(CMAKE_REQUIRED_LIBRARIES "socket")
+ check_symbol_exists(getaddrinfo "sys/types.h;sys/socket.h;netdb.h" HAVE_GETADDRINFO2)
+ if (HAVE_GETADDRINFO2 EQUAL 1)
+ set(SOCKET_LIBRARIES socket)
+ else ()
+ SET(CMAKE_REQUIRED_LIBRARIES "socket;nsl")
+ check_symbol_exists(getaddrinfo "sys/types.h;sys/socket.h;netdb.h" HAVE_GETADDRINFO3)
+ if (HAVE_GETADDRINFO3 EQUAL 1)
+ set(SOCKET_LIBRARIES socket nsl)
+ else ()
+ message(FATAL_ERROR "Cannot find name resolution library (containing symbol getaddrinfo)")
+ endif ()
+ endif ()
+ endif ()
+
+ set(CMAKE_REQUIRED_LIBRARIES ${SOCKET_LIBRARIES})
+ check_symbol_exists(socket "sys/types.h;sys/socket.h" HAVE_SOCKET)
+ if (NOT HAVE_SOCKET EQUAL 1)
+ set(CMAKE_REQUIRED_LIBRARIES socket ${SOCKET_LIBRARIES})
+ check_symbol_exists(socket "sys/types.h;sys/socket.h" HAVE_SOCKET2)
+ if (HAVE_SOCKET2 EQUAL 1)
+ set(SOCKET_LIBRARIES socket ${SOCKET_LIBRARIES})
+ else ()
+ set(CMAKE_REQUIRED_LIBRARIES socket nsl ${SOCKET_LIBRARIES})
+ check_symbol_exists(socket "sys/types.h;sys/socket.h" HAVE_SOCKET3)
+ if (HAVE_SOCKET3 EQUAL 1)
+ set(SOCKET_LIBRARIES socket nsl ${SOCKET_LIBRARIES})
+ else ()
+ message(FATAL_ERROR "Cannot find socket library (containing symbol socket)")
+ endif ()
+ endif ()
+ endif ()
+endif ()
+cmake_pop_check_state()
+
+cmake_push_check_state()
+set(CMAKE_REQUIRED_LIBRARIES ${SOCKET_LIBRARIES})
+check_symbol_exists(poll poll.h HAVE_POLL)
+if (NOT HAVE_POLL)
+ if (WIN32)
+ set(HAVE_SELECT 1)
+ else()
+ check_symbol_exists(select sys/select.h HAVE_SELECT)
+ endif()
+ if (NOT HAVE_SELECT)
+ message(FATAL_ERROR "rabbitmq-c requires poll() or select() to be available")
+ endif()
+endif()
+cmake_pop_check_state()
+
+check_library_exists(rt clock_gettime "time.h" CLOCK_GETTIME_NEEDS_LIBRT)
+check_library_exists(rt posix_spawnp "spawn.h" POSIX_SPAWNP_NEEDS_LIBRT)
+if (CLOCK_GETTIME_NEEDS_LIBRT OR POSIX_SPAWNP_NEEDS_LIBRT)
+ set(LIBRT rt)
+endif()
+
+option(ENABLE_SSL_SUPPORT "Enable SSL support" ON)
+
+if (ENABLE_SSL_SUPPORT)
+ find_package(OpenSSL 0.9.8 REQUIRED)
+
+ cmake_push_check_state()
+ set(THREADS_PREFER_PTHREAD_FLAG ON)
+ find_package(Threads REQUIRED)
+ cmake_pop_check_state()
+endif()
+
+if (MSVC)
+ set(CMAKE_C_FLAGS "/W4 /nologo ${CMAKE_C_FLAGS}")
+elseif (CMAKE_C_COMPILER_ID MATCHES ".*Clang")
+ set(CMAKE_C_FLAGS "-Wall -Wextra -Wstrict-prototypes -Wno-unused-function -fno-common -fvisibility=hidden ${CMAKE_C_FLAGS}")
+elseif (CMAKE_COMPILER_IS_GNUCC)
+ set(RMQ_C_FLAGS "-Wall -Wextra -Wstrict-prototypes -Wno-unused-function -fno-common")
+ execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
+ if (GCC_VERSION VERSION_GREATER 4.0 OR GCC_VERSION VERSION_EQUAL 4.0)
+ set(RMQ_C_FLAGS "${RMQ_C_FLAGS} -fvisibility=hidden")
+ endif()
+ set(CMAKE_C_FLAGS "${RMQ_C_FLAGS} ${CMAKE_C_FLAGS}")
+endif ()
+
+CHECK_C_COMPILER_FLAG("-std=gnu90" HAVE_GNU90)
+if (HAVE_GNU90)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90")
+else()
+ CHECK_C_COMPILER_FLAG("-std=c90" HAVE_C90)
+ if (HAVE_C90)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c90")
+ endif()
+endif()
+
+option(REGENERATE_AMQP_FRAMING "Regenerate amqp_framing.h/amqp_framing.c sources (for developer use)" OFF)
+mark_as_advanced(REGENERATE_AMQP_FRAMING)
+
+if (REGENERATE_AMQP_FRAMING)
+ find_package(PythonInterp)
+ if (NOT PYTHONINTERP_FOUND)
+ message(FATAL_ERROR "REGENERATE_AMQP_FRAMING requires Python to be available")
+ endif ()
+
+ #Determine Python Version:
+ if(PYTHON_EXECUTABLE)
+ execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c
+ "import sys; sys.stdout.write(';'.join([str(x) for x in sys.version_info[:3]]))"
+ OUTPUT_VARIABLE _VERSION
+ RESULT_VARIABLE _PYTHON_VERSION_RESULT
+ ERROR_QUIET)
+ if(NOT _PYTHON_VERSION_RESULT)
+ string(REPLACE ";" "." PYTHON_VERSION_STRING "${_VERSION}")
+ list(GET _VERSION 0 PYTHON_VERSION_MAJOR)
+ list(GET _VERSION 1 PYTHON_VERSION_MINOR)
+ list(GET _VERSION 2 PYTHON_VERSION_PATCH)
+ if(PYTHON_VERSION_PATCH EQUAL 0)
+ # it's called "Python 2.7", not "2.7.0"
+ string(REGEX REPLACE "\\.0$" "" PYTHON_VERSION_STRING "${PYTHON_VERSION_STRING}")
+ endif()
+ else()
+ # sys.version predates sys.version_info, so use that
+ execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.version)"
+ OUTPUT_VARIABLE _VERSION
+ RESULT_VARIABLE _PYTHON_VERSION_RESULT
+ ERROR_QUIET)
+ if(NOT _PYTHON_VERSION_RESULT)
+ string(REGEX REPLACE " .*" "" PYTHON_VERSION_STRING "${_VERSION}")
+ string(REGEX REPLACE "^([0-9]+)\\.[0-9]+.*" "\\1" PYTHON_VERSION_MAJOR "${PYTHON_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.([0-9])+.*" "\\1" PYTHON_VERSION_MINOR "${PYTHON_VERSION_STRING}")
+ if(PYTHON_VERSION_STRING MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+.*")
+ string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PYTHON_VERSION_PATCH "${PYTHON_VERSION_STRING}")
+ else()
+ set(PYTHON_VERSION_PATCH "0")
+ endif()
+ else()
+ # sys.version was first documented for Python 1.5, so assume
+ # this is older.
+ set(PYTHON_VERSION_STRING "1.4")
+ set(PYTHON_VERSION_MAJOR "1")
+ set(PYTHON_VERSION_MAJOR "4")
+ set(PYTHON_VERSION_MAJOR "0")
+ endif()
+ endif()
+ unset(_PYTHON_VERSION_RESULT)
+ unset(_VERSION)
+ endif(PYTHON_EXECUTABLE)
+
+ # If we're running v3.x look for a 2to3 utility
+ if (PYTHON_VERSION_MAJOR GREATER 2)
+ get_filename_component(PYTHON_EXE_DIR ${PYTHON_EXECUTABLE} PATH)
+ find_program(PYTHON_2TO3_EXECUTABLE
+ NAMES 2to3
+ HINTS ${PYTHON_EXE_DIR}
+ )
+
+ if ("PYTHON_2TO3_EXECUTABLE-NOTFOUND" STREQUAL PYTHON_2TO3_EXECUTABLE)
+ message(FATAL_ERROR "Unable to find 2to3 python utility, specify python 2.7 or specify 2to3 utility")
+ endif ()
+ endif (PYTHON_VERSION_MAJOR GREATER 2)
+
+
+ #check for json or simplejson
+ execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import json"
+ RESULT_VARIABLE CHECK_PYTHON_JSON_FAILED
+ )
+
+ if (CHECK_PYTHON_JSON_FAILED)
+ execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import simplejson"
+ RESULT_VARIABLE CHECK_PYTHON_SIMPLEJSON_FAILED
+ )
+
+ if (CHECK_PYTHON_SIMPLEJSON_FAILED)
+ message(FATAL_ERROR "REGENERATE_AMQP_FRAMING requires a python with json or simplejson modules")
+ endif (CHECK_PYTHON_SIMPLEJSON_FAILED)
+ endif (CHECK_PYTHON_JSON_FAILED)
+
+
+ find_path(AMQP_CODEGEN_DIR
+ amqp_codegen.py
+ PATHS ${CMAKE_CURRENT_SOURCE_DIR}/codegen
+ ${CMAKE_CURRENT_SOURCE_DIR}/rabbitmq-codegen
+ ${CMAKE_CURRENT_SOURCE_DIR}/../rabbitmq-codegen
+ DOC "Path to directory containing amqp_codegen.py (rabbitmq-codegen)"
+ NO_DEFAULT_PATH
+ )
+
+ if (AMQP_CODEGEN_DIR STREQUAL "AMQP_CODEGEN_DIR-NOTFOUND")
+ message(SEND_ERROR "REGENERATE_AMQP_FRAMING requires the amqp_codegen.py script. If this is a git clone you can:\n\ngit submodule init\ngit submodule update\n\n Or set AMQP_CODEGEN_DIR to directory containing amqp_codegen.py")
+ else ()
+ message(STATUS "Found amqp_codegen.py in ${AMQP_CODEGEN_DIR}")
+ endif()
+endif (REGENERATE_AMQP_FRAMING)
+
+find_package(POPT)
+find_package(XmlTo)
+find_package(Doxygen)
+
+if (POPT_FOUND AND XmlTo_FOUND)
+ set(DO_DOCS ON)
+endif()
+
+
+option(BUILD_SHARED_LIBS "Build rabbitmq-c as a shared library" ON)
+option(BUILD_STATIC_LIBS "Build rabbitmq-c as a static library" ON)
+
+option(BUILD_EXAMPLES "Build Examples" ON)
+option(BUILD_TOOLS "Build Tools (requires POPT Library)" ${POPT_FOUND})
+option(BUILD_TOOLS_DOCS "Build man pages for Tools (requires xmlto)" ${DO_DOCS})
+option(BUILD_TESTS "Build tests (run tests with make test)" ON)
+option(BUILD_API_DOCS "Build Doxygen API docs" ${DOXYGEN_FOUND})
+
+if (NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS)
+ message(FATAL_ERROR "One or both of BUILD_SHARED_LIBS or BUILD_STATIC_LIBS must be set to ON to build")
+endif()
+
+add_subdirectory(librabbitmq)
+
+if (BUILD_EXAMPLES)
+ add_subdirectory(examples)
+endif ()
+
+if (BUILD_TOOLS)
+ if (POPT_FOUND)
+ add_subdirectory(tools)
+ else ()
+ message(WARNING "POpt library was not found. Tools will not be built")
+ endif ()
+endif ()
+
+if (BUILD_TESTS)
+ if (NOT BUILD_STATIC_LIBS)
+ message(FATAL_ERROR
+ "Tests can only be built against static libraries "
+ "(set BUILD_STATIC_LIBS=ON)")
+ endif ()
+ enable_testing()
+ add_subdirectory(tests)
+endif (BUILD_TESTS)
+
+if (BUILD_API_DOCS)
+ if (NOT DOXYGEN_FOUND)
+ message(FATAL_ERROR "Doxygen is required to build the API documentation")
+ endif ()
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/docs/Doxyfile @ONLY)
+
+ add_custom_target(docs
+ COMMAND ${DOXYGEN_EXECUTABLE}
+ VERBATIM
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs
+ DEPENDS rabbitmq
+ COMMENT "Generating API documentation"
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in
+ )
+endif ()
+
+set(libs_private ${SOCKET_LIBRARIES} ${LIBRT})
+if (ENABLE_SSL_SUPPORT)
+ set(requires_private "openssl")
+ set(libs_private ${libs_private} ${CMAKE_THREAD_LIBS_INIT})
+endif()
+
+set(prefix ${CMAKE_INSTALL_PREFIX})
+set(exec_prefix "\${prefix}")
+set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
+set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
+
+configure_file(cmake/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/librabbitmq/config.h)
+configure_file(librabbitmq.pc.in ${CMAKE_CURRENT_BINARY_DIR}/librabbitmq.pc @ONLY)
+
+install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/librabbitmq.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
+ )
+
+if (BUILD_SHARED_LIBS)
+ message(STATUS "Building rabbitmq as a shared library - yes")
+else ()
+ message(STATUS "Building rabbitmq as a shared library - no")
+endif ()
+
+if (BUILD_STATIC_LIBS)
+ message(STATUS "Building rabbitmq as a static library - yes")
+else ()
+ message(STATUS "Building rabbitmq as a static library - no")
+endif ()
diff --git a/ext/librabbitmq/CONTRIBUTING.md b/ext/librabbitmq/CONTRIBUTING.md
new file mode 100644
index 000000000..20c2e4d77
--- /dev/null
+++ b/ext/librabbitmq/CONTRIBUTING.md
@@ -0,0 +1,26 @@
+Contributing to rabbitmq-c
+==========================
+
+Thanks for contributing to rabbitmq-c. I firmly believe that participation helps
+make open source software great. With that there are a few things that can be
+done to make our interaction a bit smoother.
+
+Please use the following guidelines when creating an issue or submitting a
+pull request
+
+Creating an issue
+-----------------
+When submitting an issue its helpful to know the following
+ - What version of rabbitmq-c are you using?
+ - What operating system and version are you running on?
+ - What compiler and version are you running?
+ -
+ - If its a build system issue: which build system are you using (
+
+
+Submitting a pull-request
+-------------------------
+I love to get code contributions, a few things that can help out:
+ - Make sure your commits are rebased on the current master branch
+ - Please collapse your commits down to a couple logical commits
+
diff --git a/ext/librabbitmq/ChangeLog.md b/ext/librabbitmq/ChangeLog.md
new file mode 100644
index 000000000..f9d7e4002
--- /dev/null
+++ b/ext/librabbitmq/ChangeLog.md
@@ -0,0 +1,221 @@
+# Change Log
+## v0.9.0 - 2018-05-08
+### Added:
+- amqp-publish: added support for specifying headers via the -H flag
+- Add support for specifying timeout for amqp_login calls via
+ amqp_set_handshake_timeout
+- Add support for specifying timeouts in RPC-style AMQP methods via
+ amqp_set_rpc_timeout
+- Add define for `AMQP_DEFAULT_VHOST`
+- Support for SSL SNI
+- Support for OpenSSL v1.1.0
+
+### Changed:
+- rabbitmq-c now requires Windows Vista or better
+- rabbitmq-c enables TCP keep-alive by default on platforms that support it
+- dropped support for compiling rabbitmq-c without threading support
+- OpenSSL is no longer un-intialized automatically by default. OpenSSL can be
+ explicitly initialized by calling amqp_initialize_ssl_library and
+ uninitialized by calling amqp_uninitialize_ssl_library.
+
+### Fixed:
+- Correct bugs in processing of --url flag in tools (#364).
+- Improve documentation on AMQP_SASL_METHOD_EXTERNAL (#349)
+- Improve support for compiling under mingw-w64
+- Better support for handing SIGPIPE on Linux over SSL (#401)
+- Improve publish performance on Linux by not specifying MSG_MORE on last part
+ of message.
+- Fix connection logic where multiple hostnames won't be tried if connection to
+ doesn't fail immediately (#430)
+
+### Removed:
+- autotools build system has been removed
+- many duplicate amqps_* examples, they did not add a lot of value
+
+
+## v0.8.0 - 2016-04-09
+### Added:
+- SSL: peer certificate and hostname validation can now be controlled separately
+ using `amqp_ssl_socket_set_verify_peer` and
+ `amqp_ssl_socket_set_verify_hostname`.
+- SSL: the desire SSL version range can now be specified using the
+ `amqp_ssl_socket_set_ssl_versions` function.
+- Add flags to SSL examples on controlling hostname verification.
+
+### Changed:
+- SSL: SSLv2, and SSLv3 have been disabled by default.
+- SSL: OpenSSL hostname validation has been improved.
+- Win32 debug information is built with /Z7 on MSVC to embed debug info instead
+ of using a .pdb
+
+### Fixed:
+- Connection failure results in hang on Win32 (#297, #346)
+- Rabbitmq-c may block when attempting to close an SSL socket (#313)
+- amqp_parse_url does not correctly initialize default parameters (#319)
+- x509 objects are leaked in verify_hostname (#323)
+- TCP_NOPUSH doesn't work under cygwin (#335)
+
+### Deprecated
+- SSL: `amqp_ssl_socket_set_verify` is being replaced by
+ `amqp_ssl_socket_set_verify_peer` and `amqp_ssl_socket_set_verify_hostname`.
+
+### Removed:
+- OpenVMS build system and related files.
+- Unmaintained PolarSSL, CyaSSL, and gnuTLS SSL backends
+
+## Changes since v0.7.0 (a.k.a., v0.7.1)
+- `41fa9df` Autoconf: add missing files in build system
+- `ef73c06` Win32: Use WSAEWOULDBLOCK instead of EWOULDBLOCK on Win32
+- `ceca348` CI: use travis-ci container based builds
+- `393e2df` Lib: if channel_max is 0 use server's channel_max
+- `ff47574` Lib: fix build on OpenBSD
+- `8429496...0ac6430` CI: enable CI on Mac OS X in travis-ci
+
+## Changes since v0.6.0 (a.k.a., v0.7.0)
+- `3379812` Tools: Add support for heartbeats
+- `d7029db` CI: Add continuous integration on Win32 using Appveyor
+- `a5f7ffb` Tests: only link against static libraries
+- `a16ad45...9cf7a3b` Lib: add support for EXTERNAL SASL method
+- `038a9ed` Lib: fix incorrect parameters to WSAPoll on Win32
+- `a240c69...14ae307` Lib: use non-blocking sockets internally
+- `8d1d5cc`, `5498dc6` Lib: simplify timer/timeout logic
+- `61fc4e1` Lib: add support for heartbeat checks in blocking send calls
+- `f462c0f...3546a70` Lib: Fix warnings on Win32
+- `ba9d8ba...112a54d` Lib: Add support for RabbitMQ auth failure extension
+- `fb8e318` Lib: allow calling functions to override client-properties
+- `3ef3f5f` examples: replace usleep() with nanosleep()
+- `9027a94` Lib: add AMQP_VERSION code
+- `9ee1718` Lib: fix res maybe returned uninitialized in amqp_merge_capbilities
+- `22a36db` Lib: Fix SSL_connection status check
+- `abbefd4` Lib: Fix issues with c89 compatiblity
+- `2bc1f9b...816cbfc` Lib: perf improvements when sending small messages by
+ hinting to the OS message boundaries.
+- `be2e6dd...784a0e9` Lib: add select()-based timeout implementation
+- `91db548...8d77b4c` CI: add ubsan, asan, and tsan CI builds
+
+## Changes since v0.5.2 (a.k.a., v0.6.0)
+- `e1746f9` Tools: Enable support for SSL in tools.
+- `9626dd5` Lib: ABI CHANGE: enable support for auto_delete, internal flags to
+ amqp_exchange_declare
+- `ee54e27`, `656f833` Lib: check for double-close in SSL/TCP socket impl
+- `cf2760d` Lib: allocate struct when method has no field.
+- `513ad4a` Lib: add support for SANs in OpenSSL socket impl.
+- `5348c69` Lib: add functions to get negotiated frame_max and heartbeat parms.
+
+## Changes since v0.5.1 (a.k.a., v0.5.2)
+- `fcdf0f8` Autoconf: check for htonll as declaration in a header file
+- `5790ec7` SSL: correctly report hostname verification errors.
+- `d60c28c` Build: disable OpenSSL deprecation warnings on OSX
+- `072191a` Lib: include platform, version and copyright in AMQP handshake
+- `8b448c6` Examples: print message body in amqp[s]_listen[q] examples
+- `7188e5d` Tools: Add flag to set prefetch for amqp-consume tool
+
+## Changes since v0.5.0 (a.k.a., v0.5.1)
+### Enhancements:
+- `a566929` SSL: Add support for wildcards in hostname verification (Mike
+ Steinert)
+- `a78aa8a` Lib: Use poll(2) instead of select(2) for timeouts on sockets.
+- `357bdb3` Lib: support for specifying frame and decoding pool sizes. (Mike
+ Stitt)
+- `8956003` Lib: improve invalid frame detection code.
+
+### Bug fixes:
+- `b852f84` Lib: Add missing amqp_get_server_properties() function.
+- `7001e82` Lib: Add missing ssize_t on Win32 (emazv72)
+- `c2ce2cb` Lib: Correctly specify WINVER on Win32 when unspecified.
+- `fe844e4` CMake: specify -DHAVE_CONFIG_H in examples.
+- `932de5f` Lib: correct time computation on Win32 (jestor)
+- `3e83192` HPUX: use gethrtime on HP-UX for timers.
+- `cb1b44e` HPUX: correct include location of sys/uio.h
+- `8ce585d` Lib: incorrect OOM condition when 0-lenth exchange name is received.
+- `c7716b8` CMake: correct htonll detection code on platforms defined with a
+ macro.
+- `4dc4eda` Lib: remove unused assignment.
+- `45302cf` Lib: remove range-check of channel-ids.
+
+
+## Changes since v0.4.1 (a.k.a., v0.5.0):
+### Major changes:
+- Add amqp_get_broker_properties() function 5c7c40adc1
+- Remove distro-specific packaging a5749657ee
+- Add -x flag to amqp-consume utilty 1d9c5291ff
+- Add amqp_basic_nack() public API 9b168776fb
+- Add delivery mode constants to amqp.h 5f291ea772
+- Add support for connection.blocked/connection.unblocked methods ccbc24d270
+
+### Bug fixes:
+- `f8c6cee749` Examples: Destroy amqp_envelope_t in consumer example
+- `ac88db56d3` CMake: fix generation of librabbitmq.pc
+- `d5b35afa40` CMake: fix missing POPT_INCLUDE_DIRS variable in tools/
+- `5ea6a0945a` build: provide independent locations for x64 libs
+- `fac34656c0` Doc: documentation fixes
+- `715901d675` Lib: Correct OpenSSL initialization under threaded conditions
+- `ce64e57df8` Examples: Handle unexpected frames in amqp_consumer.c
+- `bcda3e933d` CMake: Use GnuInstallDirs to generate install dirs
+- `27245a4e15` Lib: correctly handle amqp_get_monotonic_timestamp on win32
+- `693662ef5b` Tools: honor --persistent flag in publish utility
+- `01d9c3ca60` Doc: improve documentation in amqp_ssl_socket functions
+- `02d5c58ae4` autoconf: correct librabbitmq.pc generation
+- `1f4e0cc48b` Doc: improve documentation in amqp_tcp_socket functions
+
+## Changes since v0.4.0:
+### Major changes:
+- Removed distro-specific packaging d285d01
+
+### Bug fixes:
+- `a642602` FIX: destroy amqp_envelop_t object in consumer example
+- `860dd71` FIX: correct generation of librabbitmq.pc under CMake
+- `bdda7ab` FIX: amqp_socket_close() should not be exported from shlib
+- `24f4131` FIX: Use correct buf/len vars when re-starting send()
+
+## Changes since v0.3.0:
+### New Features/Enhancements:
+- `amqp_login_with_properties()` function to connect to a broker sending a
+ properties table to the broker 21b124e #101
+- SSL support (Mike Steinert) 473c865 #17
+- `amqp_simple_wait_frame_noblock()` function variant to wait for a frame
+ with a timeout f8cfc72 #119
+- Allow memory to be released on a per-channel basis with
+ `amqp_maybe_release_buffers_on_channel()` 4a2d899 #5
+- Support for AMQP heartbeats while blocking in `amqp_simple_wait_frame*()`
+ and `amqp_basic_publish()` daa0e66 aca5dc1
+- `amqp_socket_open_noblock()` for a non-blocking socket connection
+ (Bogdan Padalko) 6ad770d
+- `amqp_table_clone()` to do a deep-copy of an amqp_table_t 08af83a
+- Add option to listen to multiple keys in `amqp_consume` tool (Brian Hammond) e6c256d
+- Add contributed OpenVMS build system 448ab68
+- Higher level APIs for consuming messages 33ebeed #8
+- Doxygen-based API documentation.
+- Many improvements to error-handling and reporting
+
+### Bug Fixes:
+- `24ffaf8` FIX: autotools was broken when dependency-tracking was disabled
+- `38e741b` FIX: CMake XmlTo not found warning
+- `906f04f` FIX: htonll redeclared on Win32 v8
+- `8e41603` FIX: SIGPIPE not disabled on OS X/BSD #102
+- `872ea49` FIX: Header issues with amqp.h on Mingw on Win32 (yoniyoni)
+- `0f1f75b` FIX: potential memory leak in amqp_new_connection
+- `c9f6312` FIX: missing va_end in `amqp_login()`/`amqp_login_with_properties()`
+- `7bb64e4` FIX: include amqp_tcp_socket.h in dpkg (Tim Stewart)
+- `ba9d1f5` FIX: Report out of buffer space in `amqp_table_encode()`
+- `9496e10` FIX: Remove `abort()` on invalid parameter in `amqp_send_frame()`
+- `f209420` FIX: Remote `abort()` in `amqp_simple_wait_method()`
+- `f027518` FIX: Return error on socket lib init error
+- `0ae534a` FIX: Correctly handle 0 return val from `SSL_read()`/`SSL_write()`
+- `22e41b8` FIX: Improve error handling in socket functions
+- `33c2353` FIX: Set state->socket to NULL after `amqp_socket_close()`
+- `c83e728` FIX: Incorrect error code returned
+- `1a19879` FIX: redecl of int i in `amqp_tcp_socket_writev()`
+- `7477449` FIX: incorrect bit-shift in `amqp_error_string2()`
+- `2e37bb3` FIX: correctly handle `amqp_get_sockfd()` in `amqp_simple_wait_frame()`
+- `52a459b` FIX: Don't delete state in `amqp_tune_connection()` on error
+- `01e38dd` FIX: Correctly handle `mach_timebase_info()` failure
+- `34bffb7` FIX: Correctly disable `SIGPIPE` on platforms with `SO_NOSIGPIPE`
+- `3866433` FIX: Use correct number of bits in timer precision on MacOSX
+- `b6a1dfe` FIX: Squash OpenSSL deprecated warnings on MacOSX (Bogdan Padalko)
+- `7a217d5` FIX: Incorrect `assert()` in `wait_frame_inner()`
+- `7942af3` FIX: Correctly handle 0-length table in `amqp_table_clone()`
+- `157788e` FIX: Correctly handle 0-length strings in `amqp_basic_properties_clone()`
+- `4eaf771` FIX: Correctly handle 0-length message body in `amqp_read_message()`
+- `59f943b` FIX: Double-free SSL on connection failure
+- `7a451a4` FIX: `amqp_open_socket()` not defined
diff --git a/ext/librabbitmq/LICENSE-MIT b/ext/librabbitmq/LICENSE-MIT
new file mode 100644
index 000000000..5c7630d8b
--- /dev/null
+++ b/ext/librabbitmq/LICENSE-MIT
@@ -0,0 +1,28 @@
+Portions created by Alan Antonuk are Copyright (c) 2012-2013
+Alan Antonuk. All Rights Reserved.
+
+Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+All Rights Reserved.
+
+Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ext/librabbitmq/README.md b/ext/librabbitmq/README.md
new file mode 100644
index 000000000..525531581
--- /dev/null
+++ b/ext/librabbitmq/README.md
@@ -0,0 +1,128 @@
+# RabbitMQ C AMQP client library
+
+[](http://travis-ci.org/alanxz/rabbitmq-c)
+
+[](https://coveralls.io/github/alanxz/rabbitmq-c?branch=master)
+
+## Introduction
+
+This is a C-language AMQP client library for use with v2.0+ of the
+[RabbitMQ](http://www.rabbitmq.com/) broker.
+
+ -
+
+Announcements regarding the library are periodically made on the
+rabbitmq-c-users and cross-posted to rabbitmq-users.
+
+ -
+ -
+
+## Latest Stable Version
+
+The latest stable release of rabbitmq-c can be found at:
+
+ -
+
+## Documentation
+
+API documentation for v0.8.0+ can viewed from:
+
+
+
+## Getting started
+
+### Building and installing
+
+#### Prereqs:
+- [CMake v2.6 or better](http://www.cmake.org/)
+- A C compiler (GCC 4.4+, clang, and MSVC are test. Other compilers may also
+ work)
+- *Optionally* [OpenSSL](http://www.openssl.org/) v0.9.8+ to enable support for
+ connecting to RabbitMQ over SSL/TLS
+- *Optionally* [POpt](http://freecode.com/projects/popt) to build some handy
+ command-line tools.
+- *Optionally* [XmlTo](https://fedorahosted.org/xmlto/) to build man pages for
+ the handy command-line tools
+- *Optionally* [Doxygen](http://www.stack.nl/~dimitri/doxygen/) to build
+ developer API documentation.
+
+After downloading and extracting the source from a tarball to a directory
+([see above](#latest-stable-version)), the commands to build rabbitmq-c on most
+systems are:
+
+ mkdir build && cd build
+ cmake ..
+ cmake --build [--config Release] .
+
+The --config Release flag should be used in multi-configuration generators e.g.,
+Visual Studio or XCode.
+
+It is also possible to point the CMake GUI tool at the CMakeLists.txt in the root of
+the source tree and generate build projects or IDE workspace
+
+Installing the library and optionally specifying a prefix can be done with:
+
+ cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
+ cmake --build . [--config Release] --target install
+
+More information on CMake can be found on its FAQ (http://www.cmake.org/Wiki/CMake_FAQ)
+
+Other interesting flags that can be passed to CMake:
+
+* `BUILD_EXAMPLES=ON/OFF` toggles building the examples. ON by default.
+* `BUILD_SHARED_LIBS=ON/OFF` toggles building rabbitmq-c as a shared library.
+ ON by default.
+* `BUILD_STATIC_LIBS=ON/OFF` toggles building rabbitmq-c as a static library.
+ OFF by default.
+* `BUILD_TESTS=ON/OFF` toggles building test code. ON by default.
+* `BUILD_TOOLS=ON/OFF` toggles building the command line tools. By default
+ this is ON if the build system can find the POpt header and library.
+* `BUILD_TOOLS_DOCS=ON/OFF` toggles building the man pages for the command line
+ tools. By default this is ON if BUILD_TOOLS is ON and the build system can
+ find the XmlTo utility.
+* `ENABLE_SSL_SUPPORT=ON/OFF` toggles building rabbitmq-c with SSL support. By
+ default this is ON if the OpenSSL headers and library can be found.
+* `BUILD_API_DOCS=ON/OFF` - toggles building the Doxygen API documentation, by
+ default this is OFF
+
+## Running the examples
+
+Arrange for a RabbitMQ or other AMQP server to be running on
+`localhost` at TCP port number 5672.
+
+In one terminal, run
+
+ ./examples/amqp_listen localhost 5672 amq.direct test
+
+In another terminal,
+
+ ./examples/amqp_sendstring localhost 5672 amq.direct test "hello world"
+
+You should see output similar to the following in the listener's
+terminal window:
+
+ Delivery 1, exchange amq.direct routingkey test
+ Content-type: text/plain
+ ----
+ 00000000: 68 65 6C 6C 6F 20 77 6F : 72 6C 64 hello world
+ 0000000B:
+
+## Writing applications using `librabbitmq`
+
+Please see the `examples` directory for short examples of the use of
+the `librabbitmq` library.
+
+### Threading
+
+You cannot share a socket, an `amqp_connection_state_t`, or a channel
+between threads using `librabbitmq`. The `librabbitmq` library is
+built with event-driven, single-threaded applications in mind, and
+does not yet cater to any of the requirements of `pthread`ed
+applications.
+
+Your applications instead should open an AMQP connection (and an
+associated socket, of course) per thread. If your program needs to
+access an AMQP connection or any of its channels from more than one
+thread, it is entirely responsible for designing and implementing an
+appropriate locking scheme. It will generally be much simpler to have
+a connection exclusive to each thread that needs AMQP service.
diff --git a/ext/librabbitmq/THANKS b/ext/librabbitmq/THANKS
new file mode 100644
index 000000000..1f378eadf
--- /dev/null
+++ b/ext/librabbitmq/THANKS
@@ -0,0 +1,8 @@
+Thank-you to the following people for their contributions to the
+codebase:
+
+ - Scott Brooks / Epic Advertising
+
+ - Frank Gönninger
+
+ - Daniel Schauenberg
diff --git a/ext/librabbitmq/TODO b/ext/librabbitmq/TODO
new file mode 100644
index 000000000..179d297aa
--- /dev/null
+++ b/ext/librabbitmq/TODO
@@ -0,0 +1,9 @@
+Deal with version-mismatch-header received from the server
+
+Cope with unknown frame types better. Currently it gets horribly
+confused about frame lengths.
+
+Make client brutal by default, killing the program on any amqp
+error. Only if the user disables this behaviour will the user get to
+deal with error conditions themselves. Make use of amqp_rpc_reply
+consistent (i.e. universal), and rename it something like amqp_errno.
diff --git a/ext/librabbitmq/appveyor.yml b/ext/librabbitmq/appveyor.yml
new file mode 100644
index 000000000..0ef27f907
--- /dev/null
+++ b/ext/librabbitmq/appveyor.yml
@@ -0,0 +1,34 @@
+# appveyor configuration
+version: '{build}'
+
+# Limit history cloned. This matches what travis-CI currently does.
+clone_depth: 50
+
+environment:
+ matrix:
+ - GENERATOR: Visual Studio 12 Win64
+ BITS: 64
+ - GENERATOR: Visual Studio 12
+ BITS: 32
+
+cache:
+ - c:\deps -> appveyor.yml
+
+# borrowed from https://github.com/FreeTDS/freetds
+install:
+ # xidel (xpath command line tool)
+ - appveyor DownloadFile "https://downloads.sourceforge.net/project/videlibri/Xidel/Xidel 0.9.6/xidel-0.9.6.win32.zip"
+ - 7z x xidel-0.9.6.win32.zip xidel.exe
+ # detect version of Windows OpenSSL binaries published by the Shining Light Productions crew
+ - xidel https://slproweb.com/products/Win32OpenSSL.html --extract "(//td/a[starts-with(@href, '/download') and starts-with(text(), 'Win32 OpenSSL') and ends-with(text(), 'Light')])[1]/translate(substring-before(substring-after(text(), 'Win32 OpenSSL v'), ' Light'), '.', '_')" > openssl_ver.txt
+ - set /P OPENSSL_VER=< openssl_ver.txt
+ # OpenSSL
+ - appveyor DownloadFile https://slproweb.com/download/Win%BITS%OpenSSL-%OPENSSL_VER%.exe
+ - "Win%BITS%OpenSSL-%OPENSSL_VER%.exe /SP- /SILENT /SUPPRESSMSGBOXES /NORESTART"
+
+before_build:
+ - cmake -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON -DBUILD_TESTS=ON -DENABLE_SSL_SUPPORT=True -G"%GENERATOR%" .
+
+build:
+ project: ALL_BUILD.vcxproj
+ verbosity: normal
diff --git a/ext/librabbitmq/centos_x64/lib/librabbitmq.a b/ext/librabbitmq/centos_x64/lib/librabbitmq.a
deleted file mode 100644
index d5c3e8b42..000000000
Binary files a/ext/librabbitmq/centos_x64/lib/librabbitmq.a and /dev/null differ
diff --git a/ext/librabbitmq/cmake/CMakePushCheckState.cmake b/ext/librabbitmq/cmake/CMakePushCheckState.cmake
new file mode 100644
index 000000000..038319b40
--- /dev/null
+++ b/ext/librabbitmq/cmake/CMakePushCheckState.cmake
@@ -0,0 +1,103 @@
+# This module defines two macros:
+# CMAKE_PUSH_CHECK_STATE()
+# and
+# CMAKE_POP_CHECK_STATE()
+# These two macros can be used to save and restore the state of the variables
+# CMAKE_REQUIRED_FLAGS, CMAKE_REQUIRED_DEFINITIONS, CMAKE_REQUIRED_LIBRARIES
+# and CMAKE_REQUIRED_INCLUDES used by the various Check-files coming with CMake,
+# like e.g. check_function_exists() etc.
+# The variable contents are pushed on a stack, pushing multiple times is supported.
+# This is useful e.g. when executing such tests in a Find-module, where they have to be set,
+# but after the Find-module has been executed they should have the same value
+# as they had before.
+#
+# Usage:
+# cmake_push_check_state()
+# set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -DSOME_MORE_DEF)
+# check_function_exists(...)
+# cmake_pop_check_state()
+
+#=============================================================================
+# Copyright 2006-2011 Alexander Neundorf,
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the names of Kitware, Inc., the Insight Software Consortium,
+# nor the names of their contributors may be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER 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.
+#
+# ------------------------------------------------------------------------------
+#
+# The above copyright and license notice applies to distributions of
+# CMake in source and binary form. Some source files contain additional
+# notices of original copyright by their contributors; see each source
+# for details. Third-party software packages supplied with CMake under
+# compatible licenses provide their own copyright notices documented in
+# corresponding subdirectories.
+#
+# ------------------------------------------------------------------------------
+#
+# CMake was initially developed by Kitware with the following sponsorship:
+#
+# * National Library of Medicine at the National Institutes of Health
+# as part of the Insight Segmentation and Registration Toolkit (ITK).
+#
+# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
+# Visualization Initiative.
+#
+# * National Alliance for Medical Image Computing (NAMIC) is funded by the
+# National Institutes of Health through the NIH Roadmap for Medical Research,
+# Grant U54 EB005149.
+#
+# * Kitware, Inc.
+
+macro(CMAKE_PUSH_CHECK_STATE)
+
+ if(NOT DEFINED _CMAKE_PUSH_CHECK_STATE_COUNTER)
+ set(_CMAKE_PUSH_CHECK_STATE_COUNTER 0)
+ endif()
+
+ math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}+1")
+
+ set(_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_INCLUDES})
+ set(_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_DEFINITIONS})
+ set(_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LIBRARIES})
+ set(_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_FLAGS})
+endmacro()
+
+macro(CMAKE_POP_CHECK_STATE)
+
+# don't pop more than we pushed
+ if("${_CMAKE_PUSH_CHECK_STATE_COUNTER}" GREATER "0")
+
+ set(CMAKE_REQUIRED_INCLUDES ${_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_DEFINITIONS ${_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+
+ math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}-1")
+ endif()
+
+endmacro()
diff --git a/ext/librabbitmq/cmake/COPYING-CMAKE-SCRIPTS b/ext/librabbitmq/cmake/COPYING-CMAKE-SCRIPTS
new file mode 100644
index 000000000..53b6b71eb
--- /dev/null
+++ b/ext/librabbitmq/cmake/COPYING-CMAKE-SCRIPTS
@@ -0,0 +1,22 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ext/librabbitmq/cmake/FindPOPT.cmake b/ext/librabbitmq/cmake/FindPOPT.cmake
new file mode 100644
index 000000000..79caa0189
--- /dev/null
+++ b/ext/librabbitmq/cmake/FindPOPT.cmake
@@ -0,0 +1,39 @@
+# - Try to find the popt options processing library
+# The module will set the following variables
+#
+# POPT_FOUND - System has popt
+# POPT_INCLUDE_DIR - The popt include directory
+# POPT_LIBRARY - The libraries needed to use popt
+
+# use pkg-config to get the directories and then use these values
+# in the FIND_PATH() and FIND_LIBRARY() calls
+
+find_package(PkgConfig QUIET)
+if (PKG_CONFIG_FOUND)
+ pkg_search_module(PC_POPT QUIET popt)
+endif ()
+
+# Find the include directories
+FIND_PATH(POPT_INCLUDE_DIR
+ NAMES popt.h
+ HINTS
+ ${PC_POPT_INCLUDEDIR}
+ ${PC_POPT_INCLUDE_DIRS}
+ DOC "Path containing the popt.h include file"
+ )
+
+FIND_LIBRARY(POPT_LIBRARY
+ NAMES popt
+ HINTS
+ ${PC_POPT_LIBRARYDIR}
+ ${PC_POPT_LIBRARY_DIRS}
+ DOC "popt library path"
+ )
+
+include(FindPackageHandleStandardArgs)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(POPT
+ REQUIRED_VARS POPT_INCLUDE_DIR POPT_LIBRARY
+ VERSION_VAR PC_POPT_VERSION)
+
+MARK_AS_ADVANCED(POPT_INCLUDE_DIR POPT_LIBRARY)
diff --git a/ext/librabbitmq/cmake/FindXmlTo.cmake b/ext/librabbitmq/cmake/FindXmlTo.cmake
new file mode 100644
index 000000000..d2d4d632b
--- /dev/null
+++ b/ext/librabbitmq/cmake/FindXmlTo.cmake
@@ -0,0 +1,98 @@
+# - Convert XML docBook files to various formats
+# This will convert XML docBook files to various formats like:
+# man html txt dvi ps pdf
+# macro XMLTO(outfiles infiles... MODES modes...)
+
+find_program ( XMLTO_EXECUTABLE
+ NAMES xmlto
+ DOC "path to the xmlto docbook xslt frontend"
+)
+
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(XMLTO
+ REQUIRED_VARS XMLTO_EXECUTABLE)
+
+mark_as_advanced( XMLTO_EXECUTABLE )
+
+macro ( _XMLTO_FILE outfiles mode)
+ #special settings
+ set ( XMLTO_FILEEXT_man 1 )
+ set ( XMLTO_MODE_html xhtml-nochunks )
+
+ if ( NOT XMLTO_MODE_${mode})
+ set ( XMLTO_MODE_${mode} ${mode} )
+ endif ( NOT XMLTO_MODE_${mode} )
+ if ( NOT XMLTO_FILEEXT_${mode} )
+ set ( XMLTO_FILEEXT_${mode} ${mode} )
+ endif ( NOT XMLTO_FILEEXT_${mode} )
+
+ foreach ( dbFile ${ARGN} )
+ #TODO: set XMLTO_FILEEXT_man to value from
+ if ( "${mode}" STREQUAL "man" )
+ file ( READ "${dbFile}" _DB_FILE_CONTENTS )
+ string ( REGEX MATCH "[^<]*" XMLTO_FILEEXT_${mode} "${_DB_FILE_CONTENTS}" )
+ string ( REGEX REPLACE "^" "" XMLTO_FILEEXT_${mode} "${XMLTO_FILEEXT_${mode}}" )
+ string ( REGEX REPLACE "[[:space:]]" "" XMLTO_FILEEXT_${mode} "${XMLTO_FILEEXT_${mode}}" )
+ endif ( "${mode}" STREQUAL "man" )
+
+ get_filename_component ( dbFilePath ${CMAKE_CURRENT_BINARY_DIR}/${dbFile} PATH )
+ get_filename_component ( dbFileWE ${dbFile} NAME_WE )
+ get_filename_component ( dbFileAbsWE ${dbFilePath}/${dbFileWE} ABSOLUTE )
+
+ add_custom_command (
+ OUTPUT ${dbFileAbsWE}.${XMLTO_FILEEXT_${mode}}
+ COMMAND ${XMLTO_EXECUTABLE} ${XMLTO_COMMAND_ARGS} -o ${dbFilePath}
+ ${XMLTO_MODE_${mode}} "${CMAKE_CURRENT_SOURCE_DIR}/${dbFile}"
+ MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/${dbFile}
+ DEPENDS ${XMLTO_DEPENDS}
+ VERBATIM
+ )
+
+ set ( ${outfiles}
+ ${${outfiles}}
+ ${dbFileAbsWE}.${XMLTO_FILEEXT_${mode}}
+ )
+ endforeach ( dbFile )
+endmacro ( _XMLTO_FILE outfiles )
+
+macro ( XMLTO )
+ set ( XMLTO_MODES )
+ set ( XMLTO_FILES )
+ set ( XMLTO_HAS_MODES false )
+ set ( XMLTO_ADD_DEFAULT false )
+ foreach ( arg ${ARGN} )
+ if ( ${arg} STREQUAL "MODES" )
+ set ( XMLTO_HAS_MODES true )
+ elseif ( ${arg} STREQUAL "ALL" )
+ set ( XMLTO_ADD_DEFAULT true )
+ else ( ${arg} STREQUAL "MODES" )
+ if ( XMLTO_HAS_MODES )
+ set ( XMLTO_MODES ${XMLTO_MODES} ${arg} )
+ else ( XMLTO_HAS_MODES )
+ set ( XMLTO_FILES ${XMLTO_FILES} ${arg} )
+ endif ( XMLTO_HAS_MODES )
+ endif ( ${arg} STREQUAL "MODES" )
+ endforeach ( arg ${ARGN} )
+ if ( NOT XMLTO_MODES )
+ set ( XMLTO_MODES html )
+ endif ( NOT XMLTO_MODES )
+
+ foreach ( mode ${XMLTO_MODES} )
+ _xmlto_file ( XMLTO_FILES_${mode} ${mode} ${XMLTO_FILES} )
+ if ( XMLTO_ADD_DEFAULT )
+ add_custom_target ( ${mode} ALL
+ DEPENDS ${XMLTO_FILES_${mode}}
+ VERBATIM
+ )
+ else ( XMLTO_ADD_DEFAULT )
+ add_custom_target ( ${mode}
+ DEPENDS ${XMLTO_FILES_${mode}}
+ VERBATIM
+ )
+ endif ( XMLTO_ADD_DEFAULT )
+ endforeach ( mode )
+
+ set ( XMLTO_MODES )
+ set ( XMLTO_FILES )
+endmacro ( XMLTO )
diff --git a/ext/librabbitmq/cmake/GNUInstallDirs.cmake b/ext/librabbitmq/cmake/GNUInstallDirs.cmake
new file mode 100644
index 000000000..c8d77c6a1
--- /dev/null
+++ b/ext/librabbitmq/cmake/GNUInstallDirs.cmake
@@ -0,0 +1,205 @@
+#.rst:
+# GNUInstallDirs
+# --------------
+#
+# Define GNU standard installation directories
+#
+# Provides install directory variables as defined for GNU software:
+#
+# ::
+#
+# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
+#
+# Inclusion of this module defines the following variables:
+#
+# ::
+#
+# CMAKE_INSTALL_ - destination for files of a given type
+# CMAKE_INSTALL_FULL_ - corresponding absolute path
+#
+# where is one of:
+#
+# ::
+#
+# BINDIR - user executables (bin)
+# SBINDIR - system admin executables (sbin)
+# LIBEXECDIR - program executables (libexec)
+# SYSCONFDIR - read-only single-machine data (etc)
+# SHAREDSTATEDIR - modifiable architecture-independent data (com)
+# LOCALSTATEDIR - modifiable single-machine data (var)
+# LIBDIR - object code libraries (lib or lib64 or lib/ on Debian)
+# INCLUDEDIR - C header files (include)
+# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
+# DATAROOTDIR - read-only architecture-independent data root (share)
+# DATADIR - read-only architecture-independent data (DATAROOTDIR)
+# INFODIR - info documentation (DATAROOTDIR/info)
+# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
+# MANDIR - man documentation (DATAROOTDIR/man)
+# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
+#
+# Each CMAKE_INSTALL_ value may be passed to the DESTINATION
+# options of install() commands for the corresponding file type. If the
+# includer does not define a value the above-shown default will be used
+# and the value will appear in the cache for editing by the user. Each
+# CMAKE_INSTALL_FULL_ value contains an absolute path constructed
+# from the corresponding destination by prepending (if necessary) the
+# value of CMAKE_INSTALL_PREFIX.
+
+#=============================================================================
+# Copyright 2011 Nikita Krupen'ko
+# Copyright 2011 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# Installation directories
+#
+if(NOT DEFINED CMAKE_INSTALL_BINDIR)
+ set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
+ set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
+ set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
+ set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
+ set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
+ set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
+ set(_LIBDIR_DEFAULT "lib")
+ # Override this default 'lib' with 'lib64' iff:
+ # - we are on Linux system but NOT cross-compiling
+ # - we are NOT on debian
+ # - we are on a 64 bits system
+ # reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
+ # For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
+ # CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
+ # See http://wiki.debian.org/Multiarch
+ if(CMAKE_SYSTEM_NAME MATCHES "Linux"
+ AND NOT CMAKE_CROSSCOMPILING)
+ if (EXISTS "/etc/debian_version") # is this a debian system ?
+ if(CMAKE_LIBRARY_ARCHITECTURE)
+ set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
+ endif()
+ else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
+ if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
+ message(AUTHOR_WARNING
+ "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
+ "Please enable at least one language before including GNUInstallDirs.")
+ else()
+ if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+ set(_LIBDIR_DEFAULT "lib64")
+ endif()
+ endif()
+ endif()
+ endif()
+ set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
+ set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
+ set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
+ set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
+endif()
+
+#-----------------------------------------------------------------------------
+# Values whose defaults are relative to DATAROOTDIR. Store empty values in
+# the cache and store the defaults in local variables if the cache values are
+# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
+
+if(NOT CMAKE_INSTALL_DATADIR)
+ set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
+ set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
+endif()
+
+if(NOT CMAKE_INSTALL_INFODIR)
+ set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
+ set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
+endif()
+
+if(NOT CMAKE_INSTALL_LOCALEDIR)
+ set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
+ set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
+endif()
+
+if(NOT CMAKE_INSTALL_MANDIR)
+ set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
+ set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
+endif()
+
+if(NOT CMAKE_INSTALL_DOCDIR)
+ set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
+ set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
+endif()
+
+#-----------------------------------------------------------------------------
+
+mark_as_advanced(
+ CMAKE_INSTALL_BINDIR
+ CMAKE_INSTALL_SBINDIR
+ CMAKE_INSTALL_LIBEXECDIR
+ CMAKE_INSTALL_SYSCONFDIR
+ CMAKE_INSTALL_SHAREDSTATEDIR
+ CMAKE_INSTALL_LOCALSTATEDIR
+ CMAKE_INSTALL_LIBDIR
+ CMAKE_INSTALL_INCLUDEDIR
+ CMAKE_INSTALL_OLDINCLUDEDIR
+ CMAKE_INSTALL_DATAROOTDIR
+ CMAKE_INSTALL_DATADIR
+ CMAKE_INSTALL_INFODIR
+ CMAKE_INSTALL_LOCALEDIR
+ CMAKE_INSTALL_MANDIR
+ CMAKE_INSTALL_DOCDIR
+ )
+
+# Result directories
+#
+foreach(dir
+ BINDIR
+ SBINDIR
+ LIBEXECDIR
+ SYSCONFDIR
+ SHAREDSTATEDIR
+ LOCALSTATEDIR
+ LIBDIR
+ INCLUDEDIR
+ OLDINCLUDEDIR
+ DATAROOTDIR
+ DATADIR
+ INFODIR
+ LOCALEDIR
+ MANDIR
+ DOCDIR
+ )
+ if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
+ set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
+ else()
+ set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
+ endif()
+endforeach()
diff --git a/ext/librabbitmq/cmake/TestCInline.cmake b/ext/librabbitmq/cmake/TestCInline.cmake
new file mode 100644
index 000000000..634364687
--- /dev/null
+++ b/ext/librabbitmq/cmake/TestCInline.cmake
@@ -0,0 +1,28 @@
+#Inspired from http://www.cmake.org/Wiki/CMakeTestInline
+
+IF(NOT DEFINED C_INLINE_KEYWORD)
+
+ SET(INLINE_TEST_SRC "/* Inspired by autoconf's c.m4 */
+static inline int static_foo() {return 0\;}
+int main(int argc, char *argv[]){return 0\;}
+")
+
+ FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/CMakeTestCInline.c ${INLINE_TEST_SRC})
+
+ FOREACH(KEYWORD "inline" "__inline__" "__inline")
+ IF(NOT DEFINED C_INLINE)
+ TRY_COMPILE(C_HAS_${KEYWORD}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/CMakeTestCInline.c
+ COMPILE_DEFINITIONS "-Dinline=${KEYWORD}"
+ )
+ IF(C_HAS_${KEYWORD})
+ SET(C_INLINE ${KEYWORD})
+ ENDIF(C_HAS_${KEYWORD})
+ ENDIF(NOT DEFINED C_INLINE)
+ ENDFOREACH(KEYWORD)
+
+ SET(C_INLINE_KEYWORD ${C_INLINE} CACHE INTERNAL "The keyword needed by the C compiler to inline a function" FORCE)
+ message(STATUS "Found C inline keyword: ${C_INLINE_KEYWORD}")
+
+ENDIF(NOT DEFINED C_INLINE_KEYWORD)
diff --git a/ext/librabbitmq/cmake/config.h.in b/ext/librabbitmq/cmake/config.h.in
new file mode 100644
index 000000000..297cf40b6
--- /dev/null
+++ b/ext/librabbitmq/cmake/config.h.in
@@ -0,0 +1,14 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#ifndef __cplusplus
+# define inline ${C_INLINE_KEYWORD}
+#endif
+
+#cmakedefine HAVE_SELECT
+
+#cmakedefine HAVE_POLL
+
+#define AMQ_PLATFORM "@CMAKE_SYSTEM@"
+
+#endif /* CONFIG_H */
diff --git a/ext/librabbitmq/coverity/model.c b/ext/librabbitmq/coverity/model.c
new file mode 100644
index 000000000..dc1ad986c
--- /dev/null
+++ b/ext/librabbitmq/coverity/model.c
@@ -0,0 +1,17 @@
+/* Functions to help coverity do static analysis on rabbitmq-c */
+
+typedef struct {
+} amqp_rpc_reply_t;
+
+/* librabbitmq/amqp_private.h */
+void amqp_abort(const char* fmt, ...) { __coverity_panic__(); }
+
+/* tools/common.h */
+void die(const char* fmt, ...) { __coverity_panic__(); }
+void die_errno(int err, const char* fmt, ...) { __coverity_panic__(); }
+void die_amqp_error(int err, const char* fmt, ...) { __coverity_panic__(); }
+void die_rpc(amqp_rpc_reply_t r, const char* fmt, ...) { __coverity_panic__(); }
+
+/* examples/utils.h */
+void die_on_amqp_error(amqp_rpc_reply_t* r) { __coverity_panic__(); }
+void die_on_error(int r) { __coverity_panic__(); }
diff --git a/ext/librabbitmq/docs/Doxyfile.in b/ext/librabbitmq/docs/Doxyfile.in
new file mode 100644
index 000000000..8b5da7026
--- /dev/null
+++ b/ext/librabbitmq/docs/Doxyfile.in
@@ -0,0 +1,317 @@
+# Doxyfile 1.8.4
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = rabbitmq-c
+PROJECT_NUMBER = @VERSION@
+PROJECT_BRIEF = "C AMQP Client library for RabbitMQ"
+PROJECT_LOGO =
+OUTPUT_DIRECTORY = .
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 2
+ALIASES =
+TCL_SUBST =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+EXTENSION_MAPPING =
+MARKDOWN_SUPPORT = YES
+AUTOLINK_SUPPORT = YES
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+INLINE_GROUPED_CLASSES = NO
+INLINE_SIMPLE_STRUCTS = NO
+TYPEDEF_HIDES_STRUCT = YES
+LOOKUP_CACHE_SIZE = 0
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_PACKAGE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = NO
+FORCE_LOCAL_INCLUDES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+STRICT_PROTO_MATCHING = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+CITE_BIB_FILES =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = @CMAKE_CURRENT_SOURCE_DIR@/README.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/ChangeLog.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/librabbitmq \
+ @CMAKE_CURRENT_SOURCE_DIR@/docs
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.h \
+ *.md
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS = amqp_private.h \
+ config.h
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@ \
+ @CMAKE_CURRENT_SOURCE_DIR@/examples
+EXAMPLE_PATTERNS = *.c \
+ *.md
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE = README.md
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX = amqp_
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
+HTML_EXTRA_FILES =
+HTML_COLORSTYLE_HUE = 220
+HTML_COLORSTYLE_SAT = 100
+HTML_COLORSTYLE_GAMMA = 80
+HTML_TIMESTAMP = YES
+HTML_DYNAMIC_SECTIONS = NO
+HTML_INDEX_NUM_ENTRIES = 100
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+DOCSET_PUBLISHER_NAME = Publisher
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE = org.doxygen.Project
+QHP_VIRTUAL_FOLDER = doc
+QHP_CUST_FILTER_NAME =
+QHP_CUST_FILTER_ATTRS =
+QHP_SECT_FILTER_ATTRS =
+QHG_LOCATION =
+GENERATE_ECLIPSEHELP = NO
+ECLIPSE_DOC_ID = org.doxygen.Project
+DISABLE_INDEX = NO
+GENERATE_TREEVIEW = NO
+ENUM_VALUES_PER_LINE = 4
+TREEVIEW_WIDTH = 250
+EXT_LINKS_IN_WINDOW = NO
+FORMULA_FONTSIZE = 10
+FORMULA_TRANSPARENT = YES
+USE_MATHJAX = NO
+MATHJAX_FORMAT = HTML-CSS
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+MATHJAX_EXTENSIONS =
+MATHJAX_CODEFILE =
+SEARCHENGINE = YES
+SERVER_BASED_SEARCH = NO
+EXTERNAL_SEARCH = NO
+SEARCHENGINE_URL =
+SEARCHDATA_FILE = searchdata.xml
+EXTERNAL_SEARCH_ID =
+EXTRA_SEARCH_MAPPINGS =
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4
+EXTRA_PACKAGES =
+LATEX_HEADER =
+LATEX_FOOTER =
+LATEX_EXTRA_FILES =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+LATEX_SOURCE_CODE = NO
+LATEX_BIB_STYLE = plain
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+GENERATE_DOCBOOK = NO
+DOCBOOK_OUTPUT = docbook
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/librabbitmq \
+ @CMAKE_CURRENT_BINARY_DIR@/librabbitmq
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = AMQP_BEGIN_DECLS= \
+ AMQP_END_DECLS= \
+ AMQP_PUBLIC_FUNCTION= \
+ AMQP_PUBLIC_VARIABLE= \
+ AMQP_CALL= \
+ AMQP_DEPRECATED(x)=x
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+EXTERNAL_PAGES = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+MSCGEN_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+DOT_NUM_THREADS = 0
+DOT_FONTNAME = Helvetica
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+UML_LIMIT_NUM_FIELDS = 10
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+INTERACTIVE_SVG = NO
+DOT_PATH =
+DOTFILE_DIRS =
+MSCFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 0
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
diff --git a/ext/librabbitmq/examples/CMakeLists.txt b/ext/librabbitmq/examples/CMakeLists.txt
new file mode 100644
index 000000000..4ea8e93e4
--- /dev/null
+++ b/ext/librabbitmq/examples/CMakeLists.txt
@@ -0,0 +1,52 @@
+if (NOT BUILD_SHARED_LIBS)
+ add_definitions(-DAMQP_STATIC)
+endif()
+
+include_directories(${LIBRABBITMQ_INCLUDE_DIRS})
+
+if (WIN32)
+ set(PLATFORM_DIR win32)
+else (WIN32)
+ set(PLATFORM_DIR unix)
+endif (WIN32)
+
+set(COMMON_SRCS
+ utils.h
+ utils.c
+ ${PLATFORM_DIR}/platform_utils.c
+ )
+
+add_executable(amqp_sendstring amqp_sendstring.c ${COMMON_SRCS})
+target_link_libraries(amqp_sendstring ${RMQ_LIBRARY_TARGET})
+
+add_executable(amqp_rpc_sendstring_client amqp_rpc_sendstring_client.c ${COMMON_SRCS})
+target_link_libraries(amqp_rpc_sendstring_client ${RMQ_LIBRARY_TARGET})
+
+add_executable(amqp_exchange_declare amqp_exchange_declare.c ${COMMON_SRCS})
+target_link_libraries(amqp_exchange_declare ${RMQ_LIBRARY_TARGET})
+
+add_executable(amqp_listen amqp_listen.c ${COMMON_SRCS})
+target_link_libraries(amqp_listen ${RMQ_LIBRARY_TARGET})
+
+add_executable(amqp_producer amqp_producer.c ${COMMON_SRCS})
+target_link_libraries(amqp_producer ${RMQ_LIBRARY_TARGET})
+
+add_executable(amqp_connect_timeout amqp_connect_timeout.c ${COMMON_SRCS})
+target_link_libraries(amqp_connect_timeout ${RMQ_LIBRARY_TARGET})
+
+add_executable(amqp_consumer amqp_consumer.c ${COMMON_SRCS})
+target_link_libraries(amqp_consumer ${RMQ_LIBRARY_TARGET})
+
+add_executable(amqp_unbind amqp_unbind.c ${COMMON_SRCS})
+target_link_libraries(amqp_unbind ${RMQ_LIBRARY_TARGET})
+
+add_executable(amqp_bind amqp_bind.c ${COMMON_SRCS})
+target_link_libraries(amqp_bind ${RMQ_LIBRARY_TARGET})
+
+add_executable(amqp_listenq amqp_listenq.c ${COMMON_SRCS})
+target_link_libraries(amqp_listenq ${RMQ_LIBRARY_TARGET})
+
+if (ENABLE_SSL_SUPPORT)
+add_executable(amqp_ssl_connect amqp_ssl_connect.c ${COMMON_SRCS})
+target_link_libraries(amqp_ssl_connect ${RMQ_LIBRARY_TARGET})
+endif (ENABLE_SSL_SUPPORT)
diff --git a/ext/librabbitmq/examples/amqp_bind.c b/ext/librabbitmq/examples/amqp_bind.c
new file mode 100644
index 000000000..46371a414
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_bind.c
@@ -0,0 +1,95 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "utils.h"
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port, status;
+ char const *exchange;
+ char const *bindingkey;
+ char const *queue;
+ amqp_socket_t *socket = NULL;
+ amqp_connection_state_t conn;
+
+ if (argc < 6) {
+ fprintf(stderr, "Usage: amqp_bind host port exchange bindingkey queue\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+ exchange = argv[3];
+ bindingkey = argv[4];
+ queue = argv[5];
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ status = amqp_socket_open(socket, hostname, port);
+ if (status) {
+ die("opening TCP socket");
+ }
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+ amqp_channel_open(conn, 1);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
+
+ amqp_queue_bind(conn, 1, amqp_cstring_bytes(queue),
+ amqp_cstring_bytes(exchange), amqp_cstring_bytes(bindingkey),
+ amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Unbinding");
+
+ die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
+ "Closing channel");
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_connect_timeout.c b/ext/librabbitmq/examples/amqp_connect_timeout.c
new file mode 100644
index 000000000..21bd02e2a
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_connect_timeout.c
@@ -0,0 +1,114 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by Bogdan Padalko are Copyright (c) 2013.
+ * Bogdan Padalko. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+#else
+#include
+#endif
+
+#include "utils.h"
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port;
+ amqp_socket_t *socket;
+ amqp_connection_state_t conn;
+ struct timeval tval;
+ struct timeval *tv;
+
+ if (argc < 3) {
+ fprintf(stderr,
+ "Usage: amqp_connect_timeout host port [timeout_sec "
+ "[timeout_usec=0]]\n");
+ return 1;
+ }
+
+ if (argc > 3) {
+ tv = &tval;
+
+ tv->tv_sec = atoi(argv[3]);
+
+ if (argc > 4) {
+ tv->tv_usec = atoi(argv[4]);
+ } else {
+ tv->tv_usec = 0;
+ }
+
+ } else {
+ tv = NULL;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ die_on_error(amqp_socket_open_noblock(socket, hostname, port, tv),
+ "opening TCP socket");
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+
+ printf("Done\n");
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_consumer.c b/ext/librabbitmq/examples/amqp_consumer.c
new file mode 100644
index 000000000..93c7a21b8
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_consumer.c
@@ -0,0 +1,215 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include "utils.h"
+
+#define SUMMARY_EVERY_US 1000000
+
+static void run(amqp_connection_state_t conn) {
+ uint64_t start_time = now_microseconds();
+ int received = 0;
+ int previous_received = 0;
+ uint64_t previous_report_time = start_time;
+ uint64_t next_summary_time = start_time + SUMMARY_EVERY_US;
+
+ amqp_frame_t frame;
+
+ uint64_t now;
+
+ for (;;) {
+ amqp_rpc_reply_t ret;
+ amqp_envelope_t envelope;
+
+ now = now_microseconds();
+ if (now > next_summary_time) {
+ int countOverInterval = received - previous_received;
+ double intervalRate =
+ countOverInterval / ((now - previous_report_time) / 1000000.0);
+ printf("%d ms: Received %d - %d since last report (%d Hz)\n",
+ (int)(now - start_time) / 1000, received, countOverInterval,
+ (int)intervalRate);
+
+ previous_received = received;
+ previous_report_time = now;
+ next_summary_time += SUMMARY_EVERY_US;
+ }
+
+ amqp_maybe_release_buffers(conn);
+ ret = amqp_consume_message(conn, &envelope, NULL, 0);
+
+ if (AMQP_RESPONSE_NORMAL != ret.reply_type) {
+ if (AMQP_RESPONSE_LIBRARY_EXCEPTION == ret.reply_type &&
+ AMQP_STATUS_UNEXPECTED_STATE == ret.library_error) {
+ if (AMQP_STATUS_OK != amqp_simple_wait_frame(conn, &frame)) {
+ return;
+ }
+
+ if (AMQP_FRAME_METHOD == frame.frame_type) {
+ switch (frame.payload.method.id) {
+ case AMQP_BASIC_ACK_METHOD:
+ /* if we've turned publisher confirms on, and we've published a
+ * message here is a message being confirmed.
+ */
+ break;
+ case AMQP_BASIC_RETURN_METHOD:
+ /* if a published message couldn't be routed and the mandatory
+ * flag was set this is what would be returned. The message then
+ * needs to be read.
+ */
+ {
+ amqp_message_t message;
+ ret = amqp_read_message(conn, frame.channel, &message, 0);
+ if (AMQP_RESPONSE_NORMAL != ret.reply_type) {
+ return;
+ }
+
+ amqp_destroy_message(&message);
+ }
+
+ break;
+
+ case AMQP_CHANNEL_CLOSE_METHOD:
+ /* a channel.close method happens when a channel exception occurs,
+ * this can happen by publishing to an exchange that doesn't exist
+ * for example.
+ *
+ * In this case you would need to open another channel redeclare
+ * any queues that were declared auto-delete, and restart any
+ * consumers that were attached to the previous channel.
+ */
+ return;
+
+ case AMQP_CONNECTION_CLOSE_METHOD:
+ /* a connection.close method happens when a connection exception
+ * occurs, this can happen by trying to use a channel that isn't
+ * open for example.
+ *
+ * In this case the whole connection must be restarted.
+ */
+ return;
+
+ default:
+ fprintf(stderr, "An unexpected method was received %u\n",
+ frame.payload.method.id);
+ return;
+ }
+ }
+ }
+
+ } else {
+ amqp_destroy_envelope(&envelope);
+ }
+
+ received++;
+ }
+}
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port, status;
+ char const *exchange;
+ char const *bindingkey;
+ amqp_socket_t *socket = NULL;
+ amqp_connection_state_t conn;
+
+ amqp_bytes_t queuename;
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: amqp_consumer host port\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+ exchange = "amq.direct"; /* argv[3]; */
+ bindingkey = "test queue"; /* argv[4]; */
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ status = amqp_socket_open(socket, hostname, port);
+ if (status) {
+ die("opening TCP socket");
+ }
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+ amqp_channel_open(conn, 1);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
+
+ {
+ amqp_queue_declare_ok_t *r = amqp_queue_declare(
+ conn, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Declaring queue");
+ queuename = amqp_bytes_malloc_dup(r->queue);
+ if (queuename.bytes == NULL) {
+ fprintf(stderr, "Out of memory while copying queue name");
+ return 1;
+ }
+ }
+
+ amqp_queue_bind(conn, 1, queuename, amqp_cstring_bytes(exchange),
+ amqp_cstring_bytes(bindingkey), amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Binding queue");
+
+ amqp_basic_consume(conn, 1, queuename, amqp_empty_bytes, 0, 1, 0,
+ amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming");
+
+ run(conn);
+
+ die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
+ "Closing channel");
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_exchange_declare.c b/ext/librabbitmq/examples/amqp_exchange_declare.c
new file mode 100644
index 000000000..2199a0b32
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_exchange_declare.c
@@ -0,0 +1,94 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "utils.h"
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port, status;
+ char const *exchange;
+ char const *exchangetype;
+ amqp_socket_t *socket = NULL;
+ amqp_connection_state_t conn;
+
+ if (argc < 5) {
+ fprintf(stderr,
+ "Usage: amqp_exchange_declare host port exchange exchangetype\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+ exchange = argv[3];
+ exchangetype = argv[4];
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ status = amqp_socket_open(socket, hostname, port);
+ if (status) {
+ die("opening TCP socket");
+ }
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+ amqp_channel_open(conn, 1);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
+
+ amqp_exchange_declare(conn, 1, amqp_cstring_bytes(exchange),
+ amqp_cstring_bytes(exchangetype), 0, 0, 0, 0,
+ amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Declaring exchange");
+
+ die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
+ "Closing channel");
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_listen.c b/ext/librabbitmq/examples/amqp_listen.c
new file mode 100644
index 000000000..902622667
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_listen.c
@@ -0,0 +1,143 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include "utils.h"
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port, status;
+ char const *exchange;
+ char const *bindingkey;
+ amqp_socket_t *socket = NULL;
+ amqp_connection_state_t conn;
+
+ amqp_bytes_t queuename;
+
+ if (argc < 5) {
+ fprintf(stderr, "Usage: amqp_listen host port exchange bindingkey\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+ exchange = argv[3];
+ bindingkey = argv[4];
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ status = amqp_socket_open(socket, hostname, port);
+ if (status) {
+ die("opening TCP socket");
+ }
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+ amqp_channel_open(conn, 1);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
+
+ {
+ amqp_queue_declare_ok_t *r = amqp_queue_declare(
+ conn, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Declaring queue");
+ queuename = amqp_bytes_malloc_dup(r->queue);
+ if (queuename.bytes == NULL) {
+ fprintf(stderr, "Out of memory while copying queue name");
+ return 1;
+ }
+ }
+
+ amqp_queue_bind(conn, 1, queuename, amqp_cstring_bytes(exchange),
+ amqp_cstring_bytes(bindingkey), amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Binding queue");
+
+ amqp_basic_consume(conn, 1, queuename, amqp_empty_bytes, 0, 1, 0,
+ amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming");
+
+ {
+ for (;;) {
+ amqp_rpc_reply_t res;
+ amqp_envelope_t envelope;
+
+ amqp_maybe_release_buffers(conn);
+
+ res = amqp_consume_message(conn, &envelope, NULL, 0);
+
+ if (AMQP_RESPONSE_NORMAL != res.reply_type) {
+ break;
+ }
+
+ printf("Delivery %u, exchange %.*s routingkey %.*s\n",
+ (unsigned)envelope.delivery_tag, (int)envelope.exchange.len,
+ (char *)envelope.exchange.bytes, (int)envelope.routing_key.len,
+ (char *)envelope.routing_key.bytes);
+
+ if (envelope.message.properties._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
+ printf("Content-type: %.*s\n",
+ (int)envelope.message.properties.content_type.len,
+ (char *)envelope.message.properties.content_type.bytes);
+ }
+ printf("----\n");
+
+ amqp_dump(envelope.message.body.bytes, envelope.message.body.len);
+
+ amqp_destroy_envelope(&envelope);
+ }
+ }
+
+ die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
+ "Closing channel");
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_listenq.c b/ext/librabbitmq/examples/amqp_listenq.c
new file mode 100644
index 000000000..624dc5ccc
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_listenq.c
@@ -0,0 +1,122 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include "utils.h"
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port, status;
+ char const *queuename;
+ amqp_socket_t *socket = NULL;
+ amqp_connection_state_t conn;
+
+ if (argc < 4) {
+ fprintf(stderr, "Usage: amqp_listenq host port queuename\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+ queuename = argv[3];
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ status = amqp_socket_open(socket, hostname, port);
+ if (status) {
+ die("opening TCP socket");
+ }
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+ amqp_channel_open(conn, 1);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
+
+ amqp_basic_consume(conn, 1, amqp_cstring_bytes(queuename), amqp_empty_bytes,
+ 0, 0, 0, amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming");
+
+ for (;;) {
+ amqp_rpc_reply_t res;
+ amqp_envelope_t envelope;
+
+ amqp_maybe_release_buffers(conn);
+
+ res = amqp_consume_message(conn, &envelope, NULL, 0);
+
+ if (AMQP_RESPONSE_NORMAL != res.reply_type) {
+ break;
+ }
+
+ printf("Delivery %u, exchange %.*s routingkey %.*s\n",
+ (unsigned)envelope.delivery_tag, (int)envelope.exchange.len,
+ (char *)envelope.exchange.bytes, (int)envelope.routing_key.len,
+ (char *)envelope.routing_key.bytes);
+
+ if (envelope.message.properties._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
+ printf("Content-type: %.*s\n",
+ (int)envelope.message.properties.content_type.len,
+ (char *)envelope.message.properties.content_type.bytes);
+ }
+ printf("----\n");
+
+ amqp_dump(envelope.message.body.bytes, envelope.message.body.len);
+
+ amqp_destroy_envelope(&envelope);
+ }
+
+ die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
+ "Closing channel");
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_producer.c b/ext/librabbitmq/examples/amqp_producer.c
new file mode 100644
index 000000000..6e78fcb66
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_producer.c
@@ -0,0 +1,150 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "utils.h"
+
+#define SUMMARY_EVERY_US 1000000
+
+static void send_batch(amqp_connection_state_t conn, char const *queue_name,
+ int rate_limit, int message_count) {
+ uint64_t start_time = now_microseconds();
+ int i;
+ int sent = 0;
+ int previous_sent = 0;
+ uint64_t previous_report_time = start_time;
+ uint64_t next_summary_time = start_time + SUMMARY_EVERY_US;
+
+ char message[256];
+ amqp_bytes_t message_bytes;
+
+ for (i = 0; i < (int)sizeof(message); i++) {
+ message[i] = i & 0xff;
+ }
+
+ message_bytes.len = sizeof(message);
+ message_bytes.bytes = message;
+
+ for (i = 0; i < message_count; i++) {
+ uint64_t now = now_microseconds();
+
+ die_on_error(amqp_basic_publish(conn, 1, amqp_cstring_bytes("amq.direct"),
+ amqp_cstring_bytes(queue_name), 0, 0, NULL,
+ message_bytes),
+ "Publishing");
+ sent++;
+ if (now > next_summary_time) {
+ int countOverInterval = sent - previous_sent;
+ double intervalRate =
+ countOverInterval / ((now - previous_report_time) / 1000000.0);
+ printf("%d ms: Sent %d - %d since last report (%d Hz)\n",
+ (int)(now - start_time) / 1000, sent, countOverInterval,
+ (int)intervalRate);
+
+ previous_sent = sent;
+ previous_report_time = now;
+ next_summary_time += SUMMARY_EVERY_US;
+ }
+
+ while (((i * 1000000.0) / (now - start_time)) > rate_limit) {
+ microsleep(2000);
+ now = now_microseconds();
+ }
+ }
+
+ {
+ uint64_t stop_time = now_microseconds();
+ int total_delta = (int)(stop_time - start_time);
+
+ printf("PRODUCER - Message count: %d\n", message_count);
+ printf("Total time, milliseconds: %d\n", total_delta / 1000);
+ printf("Overall messages-per-second: %g\n",
+ (message_count / (total_delta / 1000000.0)));
+ }
+}
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port, status;
+ int rate_limit;
+ int message_count;
+ amqp_socket_t *socket = NULL;
+ amqp_connection_state_t conn;
+
+ if (argc < 5) {
+ fprintf(stderr,
+ "Usage: amqp_producer host port rate_limit message_count\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+ rate_limit = atoi(argv[3]);
+ message_count = atoi(argv[4]);
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ status = amqp_socket_open(socket, hostname, port);
+ if (status) {
+ die("opening TCP socket");
+ }
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+ amqp_channel_open(conn, 1);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
+
+ send_batch(conn, "test queue", rate_limit, message_count);
+
+ die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
+ "Closing channel");
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_rpc_sendstring_client.c b/ext/librabbitmq/examples/amqp_rpc_sendstring_client.c
new file mode 100644
index 000000000..59918e531
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_rpc_sendstring_client.c
@@ -0,0 +1,243 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include "utils.h"
+
+int main(int argc, char *argv[]) {
+ char const *hostname;
+ int port, status;
+ char const *exchange;
+ char const *routingkey;
+ char const *messagebody;
+ amqp_socket_t *socket = NULL;
+ amqp_connection_state_t conn;
+ amqp_bytes_t reply_to_queue;
+
+ if (argc < 6) { /* minimum number of mandatory arguments */
+ fprintf(stderr,
+ "usage:\namqp_rpc_sendstring_client host port exchange routingkey "
+ "messagebody\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+ exchange = argv[3];
+ routingkey = argv[4];
+ messagebody = argv[5];
+
+ /*
+ establish a channel that is used to connect RabbitMQ server
+ */
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ status = amqp_socket_open(socket, hostname, port);
+ if (status) {
+ die("opening TCP socket");
+ }
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+ amqp_channel_open(conn, 1);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
+
+ /*
+ create private reply_to queue
+ */
+
+ {
+ amqp_queue_declare_ok_t *r = amqp_queue_declare(
+ conn, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Declaring queue");
+ reply_to_queue = amqp_bytes_malloc_dup(r->queue);
+ if (reply_to_queue.bytes == NULL) {
+ fprintf(stderr, "Out of memory while copying queue name");
+ return 1;
+ }
+ }
+
+ /*
+ send the message
+ */
+
+ {
+ /*
+ set properties
+ */
+ amqp_basic_properties_t props;
+ props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
+ AMQP_BASIC_DELIVERY_MODE_FLAG | AMQP_BASIC_REPLY_TO_FLAG |
+ AMQP_BASIC_CORRELATION_ID_FLAG;
+ props.content_type = amqp_cstring_bytes("text/plain");
+ props.delivery_mode = 2; /* persistent delivery mode */
+ props.reply_to = amqp_bytes_malloc_dup(reply_to_queue);
+ if (props.reply_to.bytes == NULL) {
+ fprintf(stderr, "Out of memory while copying queue name");
+ return 1;
+ }
+ props.correlation_id = amqp_cstring_bytes("1");
+
+ /*
+ publish
+ */
+ die_on_error(amqp_basic_publish(conn, 1, amqp_cstring_bytes(exchange),
+ amqp_cstring_bytes(routingkey), 0, 0,
+ &props, amqp_cstring_bytes(messagebody)),
+ "Publishing");
+
+ amqp_bytes_free(props.reply_to);
+ }
+
+ /*
+ wait an answer
+ */
+
+ {
+ amqp_basic_consume(conn, 1, reply_to_queue, amqp_empty_bytes, 0, 1, 0,
+ amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming");
+ amqp_bytes_free(reply_to_queue);
+
+ {
+ amqp_frame_t frame;
+ int result;
+
+ amqp_basic_deliver_t *d;
+ amqp_basic_properties_t *p;
+ size_t body_target;
+ size_t body_received;
+
+ for (;;) {
+ amqp_maybe_release_buffers(conn);
+ result = amqp_simple_wait_frame(conn, &frame);
+ printf("Result: %d\n", result);
+ if (result < 0) {
+ break;
+ }
+
+ printf("Frame type: %u channel: %u\n", frame.frame_type, frame.channel);
+ if (frame.frame_type != AMQP_FRAME_METHOD) {
+ continue;
+ }
+
+ printf("Method: %s\n", amqp_method_name(frame.payload.method.id));
+ if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) {
+ continue;
+ }
+
+ d = (amqp_basic_deliver_t *)frame.payload.method.decoded;
+ printf("Delivery: %u exchange: %.*s routingkey: %.*s\n",
+ (unsigned)d->delivery_tag, (int)d->exchange.len,
+ (char *)d->exchange.bytes, (int)d->routing_key.len,
+ (char *)d->routing_key.bytes);
+
+ result = amqp_simple_wait_frame(conn, &frame);
+ if (result < 0) {
+ break;
+ }
+
+ if (frame.frame_type != AMQP_FRAME_HEADER) {
+ fprintf(stderr, "Expected header!");
+ abort();
+ }
+ p = (amqp_basic_properties_t *)frame.payload.properties.decoded;
+ if (p->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
+ printf("Content-type: %.*s\n", (int)p->content_type.len,
+ (char *)p->content_type.bytes);
+ }
+ printf("----\n");
+
+ body_target = (size_t)frame.payload.properties.body_size;
+ body_received = 0;
+
+ while (body_received < body_target) {
+ result = amqp_simple_wait_frame(conn, &frame);
+ if (result < 0) {
+ break;
+ }
+
+ if (frame.frame_type != AMQP_FRAME_BODY) {
+ fprintf(stderr, "Expected body!");
+ abort();
+ }
+
+ body_received += frame.payload.body_fragment.len;
+ assert(body_received <= body_target);
+
+ amqp_dump(frame.payload.body_fragment.bytes,
+ frame.payload.body_fragment.len);
+ }
+
+ if (body_received != body_target) {
+ /* Can only happen when amqp_simple_wait_frame returns <= 0 */
+ /* We break here to close the connection */
+ break;
+ }
+
+ /* everything was fine, we can quit now because we received the reply */
+ break;
+ }
+ }
+ }
+
+ /*
+ closing
+ */
+
+ die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
+ "Closing channel");
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_sendstring.c b/ext/librabbitmq/examples/amqp_sendstring.c
new file mode 100644
index 000000000..75492aa36
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_sendstring.c
@@ -0,0 +1,103 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "utils.h"
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port, status;
+ char const *exchange;
+ char const *routingkey;
+ char const *messagebody;
+ amqp_socket_t *socket = NULL;
+ amqp_connection_state_t conn;
+
+ if (argc < 6) {
+ fprintf(
+ stderr,
+ "Usage: amqp_sendstring host port exchange routingkey messagebody\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+ exchange = argv[3];
+ routingkey = argv[4];
+ messagebody = argv[5];
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ status = amqp_socket_open(socket, hostname, port);
+ if (status) {
+ die("opening TCP socket");
+ }
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+ amqp_channel_open(conn, 1);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
+
+ {
+ amqp_basic_properties_t props;
+ props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG;
+ props.content_type = amqp_cstring_bytes("text/plain");
+ props.delivery_mode = 2; /* persistent delivery mode */
+ die_on_error(amqp_basic_publish(conn, 1, amqp_cstring_bytes(exchange),
+ amqp_cstring_bytes(routingkey), 0, 0,
+ &props, amqp_cstring_bytes(messagebody)),
+ "Publishing");
+ }
+
+ die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
+ "Closing channel");
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_ssl_connect.c b/ext/librabbitmq/examples/amqp_ssl_connect.c
new file mode 100644
index 000000000..3674c3337
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_ssl_connect.c
@@ -0,0 +1,135 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by Mike Steinert are Copyright (c) 2012-2013
+ * Mike Steinert. All Rights Reserved.
+ *
+ * Portions created by Bogdan Padalko are Copyright (c) 2013.
+ * Bogdan Padalko. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+#else
+#include
+#endif
+
+#include "utils.h"
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port;
+ int timeout;
+ amqp_socket_t *socket;
+ amqp_connection_state_t conn;
+ struct timeval tval;
+ struct timeval *tv;
+
+ if (argc < 3) {
+ fprintf(stderr,
+ "Usage: amqps_connect_timeout host port timeout_sec "
+ "[cacert.pem [verifypeer] [verifyhostname] [key.pem cert.pem]]\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+
+ timeout = atoi(argv[3]);
+ if (timeout > 0) {
+ tv = &tval;
+
+ tv->tv_sec = timeout;
+ tv->tv_usec = 0;
+ } else {
+ tv = NULL;
+ }
+
+ conn = amqp_new_connection();
+
+ socket = amqp_ssl_socket_new(conn);
+ if (!socket) {
+ die("creating SSL/TLS socket");
+ }
+
+ amqp_ssl_socket_set_verify_peer(socket, 0);
+ amqp_ssl_socket_set_verify_hostname(socket, 0);
+
+ if (argc > 5) {
+ int nextarg = 5;
+ die_on_error(amqp_ssl_socket_set_cacert(socket, argv[4]),
+ "setting CA certificate");
+ if (argc > nextarg && !strcmp("verifypeer", argv[nextarg])) {
+ amqp_ssl_socket_set_verify_peer(socket, 1);
+ nextarg++;
+ }
+ if (argc > nextarg && !strcmp("verifyhostname", argv[nextarg])) {
+ amqp_ssl_socket_set_verify_hostname(socket, 1);
+ nextarg++;
+ }
+ if (argc > nextarg + 1) {
+ die_on_error(
+ amqp_ssl_socket_set_key(socket, argv[nextarg + 1], argv[nextarg]),
+ "setting client key");
+ }
+ }
+
+ die_on_error(amqp_socket_open_noblock(socket, hostname, port, tv),
+ "opening SSL/TLS connection");
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+ die_on_error(amqp_uninitialize_ssl_library(), "Uninitializing SSL library");
+
+ printf("Done\n");
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/amqp_unbind.c b/ext/librabbitmq/examples/amqp_unbind.c
new file mode 100644
index 000000000..aea07381a
--- /dev/null
+++ b/ext/librabbitmq/examples/amqp_unbind.c
@@ -0,0 +1,95 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "utils.h"
+
+int main(int argc, char const *const *argv) {
+ char const *hostname;
+ int port, status;
+ char const *exchange;
+ char const *bindingkey;
+ char const *queue;
+ amqp_socket_t *socket = NULL;
+ amqp_connection_state_t conn;
+
+ if (argc < 6) {
+ fprintf(stderr, "Usage: amqp_unbind host port exchange bindingkey queue\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ port = atoi(argv[2]);
+ exchange = argv[3];
+ bindingkey = argv[4];
+ queue = argv[5];
+
+ conn = amqp_new_connection();
+
+ socket = amqp_tcp_socket_new(conn);
+ if (!socket) {
+ die("creating TCP socket");
+ }
+
+ status = amqp_socket_open(socket, hostname, port);
+ if (status) {
+ die("opening TCP socket");
+ }
+
+ die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
+ "guest", "guest"),
+ "Logging in");
+ amqp_channel_open(conn, 1);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
+
+ amqp_queue_unbind(conn, 1, amqp_cstring_bytes(queue),
+ amqp_cstring_bytes(exchange),
+ amqp_cstring_bytes(bindingkey), amqp_empty_table);
+ die_on_amqp_error(amqp_get_rpc_reply(conn), "Unbinding");
+
+ die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
+ "Closing channel");
+ die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
+ "Closing connection");
+ die_on_error(amqp_destroy_connection(conn), "Ending connection");
+ return 0;
+}
diff --git a/ext/librabbitmq/examples/unix/platform_utils.c b/ext/librabbitmq/examples/unix/platform_utils.c
new file mode 100644
index 000000000..e420b823a
--- /dev/null
+++ b/ext/librabbitmq/examples/unix/platform_utils.c
@@ -0,0 +1,52 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+
+uint64_t now_microseconds(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
+}
+
+void microsleep(int usec) {
+ struct timespec req;
+ req.tv_sec = 0;
+ req.tv_nsec = 1000 * usec;
+ nanosleep(&req, NULL);
+}
diff --git a/ext/librabbitmq/examples/utils.c b/ext/librabbitmq/examples/utils.c
new file mode 100644
index 000000000..8d1b4c63c
--- /dev/null
+++ b/ext/librabbitmq/examples/utils.c
@@ -0,0 +1,188 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "utils.h"
+
+void die(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+void die_on_error(int x, char const *context) {
+ if (x < 0) {
+ fprintf(stderr, "%s: %s\n", context, amqp_error_string2(x));
+ exit(1);
+ }
+}
+
+void die_on_amqp_error(amqp_rpc_reply_t x, char const *context) {
+ switch (x.reply_type) {
+ case AMQP_RESPONSE_NORMAL:
+ return;
+
+ case AMQP_RESPONSE_NONE:
+ fprintf(stderr, "%s: missing RPC reply type!\n", context);
+ break;
+
+ case AMQP_RESPONSE_LIBRARY_EXCEPTION:
+ fprintf(stderr, "%s: %s\n", context, amqp_error_string2(x.library_error));
+ break;
+
+ case AMQP_RESPONSE_SERVER_EXCEPTION:
+ switch (x.reply.id) {
+ case AMQP_CONNECTION_CLOSE_METHOD: {
+ amqp_connection_close_t *m =
+ (amqp_connection_close_t *)x.reply.decoded;
+ fprintf(stderr, "%s: server connection error %uh, message: %.*s\n",
+ context, m->reply_code, (int)m->reply_text.len,
+ (char *)m->reply_text.bytes);
+ break;
+ }
+ case AMQP_CHANNEL_CLOSE_METHOD: {
+ amqp_channel_close_t *m = (amqp_channel_close_t *)x.reply.decoded;
+ fprintf(stderr, "%s: server channel error %uh, message: %.*s\n",
+ context, m->reply_code, (int)m->reply_text.len,
+ (char *)m->reply_text.bytes);
+ break;
+ }
+ default:
+ fprintf(stderr, "%s: unknown server error, method id 0x%08X\n",
+ context, x.reply.id);
+ break;
+ }
+ break;
+ }
+
+ exit(1);
+}
+
+static void dump_row(long count, int numinrow, int *chs) {
+ int i;
+
+ printf("%08lX:", count - numinrow);
+
+ if (numinrow > 0) {
+ for (i = 0; i < numinrow; i++) {
+ if (i == 8) {
+ printf(" :");
+ }
+ printf(" %02X", chs[i]);
+ }
+ for (i = numinrow; i < 16; i++) {
+ if (i == 8) {
+ printf(" :");
+ }
+ printf(" ");
+ }
+ printf(" ");
+ for (i = 0; i < numinrow; i++) {
+ if (isprint(chs[i])) {
+ printf("%c", chs[i]);
+ } else {
+ printf(".");
+ }
+ }
+ }
+ printf("\n");
+}
+
+static int rows_eq(int *a, int *b) {
+ int i;
+
+ for (i = 0; i < 16; i++)
+ if (a[i] != b[i]) {
+ return 0;
+ }
+
+ return 1;
+}
+
+void amqp_dump(void const *buffer, size_t len) {
+ unsigned char *buf = (unsigned char *)buffer;
+ long count = 0;
+ int numinrow = 0;
+ int chs[16];
+ int oldchs[16] = {0};
+ int showed_dots = 0;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ int ch = buf[i];
+
+ if (numinrow == 16) {
+ int j;
+
+ if (rows_eq(oldchs, chs)) {
+ if (!showed_dots) {
+ showed_dots = 1;
+ printf(
+ " .. .. .. .. .. .. .. .. : .. .. .. .. .. .. .. ..\n");
+ }
+ } else {
+ showed_dots = 0;
+ dump_row(count, numinrow, chs);
+ }
+
+ for (j = 0; j < 16; j++) {
+ oldchs[j] = chs[j];
+ }
+
+ numinrow = 0;
+ }
+
+ count++;
+ chs[numinrow++] = ch;
+ }
+
+ dump_row(count, numinrow, chs);
+
+ if (numinrow != 0) {
+ printf("%08lX:\n", count);
+ }
+}
diff --git a/ext/librabbitmq/examples/utils.h b/ext/librabbitmq/examples/utils.h
new file mode 100644
index 000000000..0fa7392ab
--- /dev/null
+++ b/ext/librabbitmq/examples/utils.h
@@ -0,0 +1,48 @@
+#ifndef librabbitmq_examples_utils_h
+#define librabbitmq_examples_utils_h
+
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+void die(const char *fmt, ...);
+extern void die_on_error(int x, char const *context);
+extern void die_on_amqp_error(amqp_rpc_reply_t x, char const *context);
+
+extern void amqp_dump(void const *buffer, size_t len);
+
+extern uint64_t now_microseconds(void);
+extern void microsleep(int usec);
+
+#endif
diff --git a/ext/librabbitmq/examples/win32/platform_utils.c b/ext/librabbitmq/examples/win32/platform_utils.c
new file mode 100644
index 000000000..49fd377e3
--- /dev/null
+++ b/ext/librabbitmq/examples/win32/platform_utils.c
@@ -0,0 +1,47 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+
+#include
+
+uint64_t now_microseconds(void) {
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ return (((uint64_t)ft.dwHighDateTime << 32) | (uint64_t)ft.dwLowDateTime) /
+ 10;
+}
+
+void microsleep(int usec) { Sleep(usec / 1000); }
diff --git a/ext/librabbitmq/librabbitmq.pc.in b/ext/librabbitmq/librabbitmq.pc.in
new file mode 100644
index 000000000..17c1e0835
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: rabbitmq-c
+Description: An AMQP 0-9-1 client library
+Version: @VERSION@
+URL: https://github.com/alanxz/rabbitmq-c
+Requires.private: @requires_private@
+Libs: -L${libdir} -lrabbitmq
+Libs.private: @libs_private@
+CFlags: -I${includedir}
diff --git a/ext/librabbitmq/librabbitmq/CMakeLists.txt b/ext/librabbitmq/librabbitmq/CMakeLists.txt
new file mode 100644
index 000000000..bd5369a8f
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/CMakeLists.txt
@@ -0,0 +1,186 @@
+project(librabbitmq "C")
+
+if (REGENERATE_AMQP_FRAMING)
+ set(AMQP_CODEGEN_PY "${CMAKE_CURRENT_BINARY_DIR}/amqp_codegen.py")
+ set(CODEGEN_PY "${CMAKE_CURRENT_BINARY_DIR}/codegen.py")
+ set(AMQP_SPEC_JSON_PATH "${AMQP_CODEGEN_DIR}/amqp-rabbitmq-0.9.1.json")
+ set(AMQP_FRAMING_H_PATH ${CMAKE_CURRENT_BINARY_DIR}/amqp_framing.h)
+ set(AMQP_FRAMING_C_PATH ${CMAKE_CURRENT_BINARY_DIR}/amqp_framing.c)
+
+ if (PYTHON_VERSION_MAJOR GREATER 2)
+ set(CONVERT_CODEGEN ${PYTHON_2TO3_EXECUTABLE} -w ${CODEGEN_PY} > codegen_2to3.out)
+ set(CONVERT_AMQP_CODEGEN ${PYTHON_2TO3_EXECUTABLE} -w ${AMQP_CODEGEN_PY} > amqp_codegen_2to3.out)
+ else ()
+ set(CONVERT_CODEGEN "")
+ set(CONVERT_AMQP_CODEGEN "")
+ endif ()
+
+ add_custom_command(
+ OUTPUT ${CODEGEN_PY}
+ COMMAND ${CMAKE_COMMAND} ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/codegen.py ${CODEGEN_PY}
+ COMMAND ${CONVERT_CODEGEN}
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/codegen.py
+ VERBATIM)
+
+ add_custom_command(
+ OUTPUT ${AMQP_CODEGEN_PY}
+ COMMAND ${CMAKE_COMMAND} ARGS -E copy ${AMQP_CODEGEN_DIR}/amqp_codegen.py ${AMQP_CODEGEN_PY}
+ COMMAND ${CONVERT_AMQP_CODEGEN}
+ DEPENDS ${AMQP_CODEGEN_DIR}/amqp_codegen.py ${AMQP_CODEGEN_TARGET}
+ VERBATIM)
+
+ add_custom_command(
+ OUTPUT ${AMQP_FRAMING_H_PATH}
+ COMMAND ${PYTHON_EXECUTABLE} ARGS ${CODEGEN_PY} header ${AMQP_SPEC_JSON_PATH} ${AMQP_FRAMING_H_PATH}
+ DEPENDS ${AMQP_SPEC_JSON_PATH} ${CODEGEN_PY} ${AMQP_CODEGEN_PY}
+ VERBATIM)
+
+ add_custom_command(
+ OUTPUT ${AMQP_FRAMING_C_PATH}
+ COMMAND ${PYTHON_EXECUTABLE} ARGS ${CODEGEN_PY} body ${AMQP_SPEC_JSON_PATH} ${AMQP_FRAMING_C_PATH}
+ DEPENDS ${AMQP_SPEC_JSON_PATH} ${CODEGEN_PY} ${AMQP_CODEGEN_PY}
+ VERBATIM)
+else (REGENERATE_AMQP_FRAMING)
+ set(AMQP_FRAMING_H_PATH ${CMAKE_CURRENT_SOURCE_DIR}/amqp_framing.h)
+ set(AMQP_FRAMING_C_PATH ${CMAKE_CURRENT_SOURCE_DIR}/amqp_framing.c)
+endif (REGENERATE_AMQP_FRAMING)
+
+if(WIN32)
+ set(SOCKET_IMPL "win32")
+else(WIN32)
+ set(SOCKET_IMPL "unix")
+endif(WIN32)
+
+if(MSVC)
+ if(MSVC_VERSION LESS 1600)
+ set(MSINTTYPES_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/win32/msinttypes")
+ set(STDINT_H_INSTALL_FILE "${CMAKE_CURRENT_SOURCE_DIR}/win32/msinttypes/stdint.h")
+ endif(MSVC_VERSION LESS 1600)
+endif(MSVC)
+
+# NOTE: order is important here: if we generate amqp_framing.h/.c it'll be in the
+# binary directory, and should shadow whats in the source directory
+set(LIBRABBITMQ_INCLUDE_DIRS
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${SOCKET_IMPL}
+ ${MSINTTYPES_INCLUDE}
+ )
+
+include_directories(${LIBRABBITMQ_INCLUDE_DIRS})
+
+set(LIBRABBITMQ_INCLUDE_DIRS
+ ${LIBRABBITMQ_INCLUDE_DIRS}
+ PARENT_SCOPE)
+
+add_definitions(-DHAVE_CONFIG_H)
+
+if (ENABLE_SSL_SUPPORT)
+ add_definitions(-DWITH_SSL=1)
+ set(AMQP_SSL_SOCKET_H_PATH amqp_ssl_socket.h)
+
+ set(AMQP_SSL_SRCS ${AMQP_SSL_SOCKET_H_PATH}
+ amqp_openssl.c
+ amqp_openssl_hostname_validation.c
+ amqp_openssl_hostname_validation.h
+ amqp_hostcheck.c
+ amqp_hostcheck.h
+ amqp_openssl_bio.c
+ amqp_openssl_bio.h
+ )
+ include_directories(${OPENSSL_INCLUDE_DIR})
+ set(AMQP_SSL_LIBS ${OPENSSL_LIBRARIES})
+ if (APPLE)
+ # Apple has deprecated OpenSSL in 10.7+. This disables that warning.
+ set_source_files_properties(${AMQP_SSL_SRCS}
+ PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations)
+ endif()
+
+ if (WIN32)
+ set(AMQP_SSL_SRCS ${AMQP_SSL_SRCS} win32/threads.h win32/threads.c)
+ else()
+ set(AMQP_SSL_SRCS ${AMQP_SSL_SRCS} unix/threads.h)
+ endif()
+endif()
+
+set(RABBITMQ_SOURCES
+ ${AMQP_FRAMING_H_PATH}
+ ${AMQP_FRAMING_C_PATH}
+ amqp_api.c amqp.h amqp_connection.c amqp_mem.c amqp_private.h amqp_socket.c
+ amqp_table.c amqp_url.c amqp_socket.h amqp_tcp_socket.c amqp_tcp_socket.h
+ amqp_time.c amqp_time.h
+ amqp_consumer.c
+ ${AMQP_SSL_SRCS}
+)
+
+add_definitions(-DAMQP_BUILD)
+
+set(RMQ_LIBRARIES ${AMQP_SSL_LIBS} ${SOCKET_LIBRARIES} ${LIBRT} ${CMAKE_THREAD_LIBS_INIT})
+
+if (BUILD_SHARED_LIBS)
+ add_library(rabbitmq SHARED ${RABBITMQ_SOURCES})
+ if (THREADS_HAVE_PTHREAD_ARG)
+ target_compile_options(rabbitmq PUBLIC "-pthread")
+ endif()
+
+ target_link_libraries(rabbitmq ${RMQ_LIBRARIES})
+
+ if (WIN32)
+ set_target_properties(rabbitmq PROPERTIES VERSION ${RMQ_VERSION} OUTPUT_NAME rabbitmq.${RMQ_SOVERSION})
+ else (WIN32)
+ set_target_properties(rabbitmq PROPERTIES VERSION ${RMQ_VERSION} SOVERSION ${RMQ_SOVERSION})
+ endif (WIN32)
+
+ install(TARGETS rabbitmq
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+
+ set(RMQ_LIBRARY_TARGET rabbitmq)
+endif (BUILD_SHARED_LIBS)
+
+if (BUILD_STATIC_LIBS)
+ add_library(rabbitmq-static STATIC ${RABBITMQ_SOURCES})
+ if (THREADS_HAVE_PTHREAD_ARG)
+ target_compile_options(rabbitmq-static PUBLIC "-pthread")
+ endif()
+
+ target_link_libraries(rabbitmq-static ${RMQ_LIBRARIES})
+
+ set_target_properties(rabbitmq-static PROPERTIES COMPILE_DEFINITIONS AMQP_STATIC)
+ if (WIN32)
+ set_target_properties(rabbitmq-static PROPERTIES
+ VERSION ${RMQ_VERSION}
+ OUTPUT_NAME librabbitmq.${RMQ_SOVERSION})
+
+ if(MSVC)
+ set_target_properties(rabbitmq-static PROPERTIES
+ # Embed debugging info in the library itself instead of generating
+ # a .pdb file.
+ COMPILE_OPTIONS "/Z7")
+ endif(MSVC)
+
+ else (WIN32)
+ set_target_properties(rabbitmq-static PROPERTIES VERSION ${RMQ_VERSION} SOVERSION ${RMQ_SOVERSION} OUTPUT_NAME rabbitmq)
+ endif (WIN32)
+
+ install(TARGETS rabbitmq-static
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+
+ if (NOT DEFINED RMQ_LIBRARY_TARGET)
+ set(RMQ_LIBRARY_TARGET rabbitmq-static)
+ endif ()
+endif (BUILD_STATIC_LIBS)
+
+install(FILES
+ amqp.h
+ ${AMQP_FRAMING_H_PATH}
+ amqp_tcp_socket.h
+ ${AMQP_SSL_SOCKET_H_PATH}
+ ${STDINT_H_INSTALL_FILE}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ )
+
+set(RMQ_LIBRARY_TARGET ${RMQ_LIBRARY_TARGET} PARENT_SCOPE)
diff --git a/ext/librabbitmq/centos_x64/include/amqp.h b/ext/librabbitmq/librabbitmq/amqp.h
similarity index 99%
rename from ext/librabbitmq/centos_x64/include/amqp.h
rename to ext/librabbitmq/librabbitmq/amqp.h
index 2983b1665..734abb8d9 100644
--- a/ext/librabbitmq/centos_x64/include/amqp.h
+++ b/ext/librabbitmq/librabbitmq/amqp.h
@@ -219,9 +219,9 @@ AMQP_BEGIN_DECLS
*/
#define AMQP_VERSION_MAJOR 0
-#define AMQP_VERSION_MINOR 10
+#define AMQP_VERSION_MINOR 9
#define AMQP_VERSION_PATCH 0
-#define AMQP_VERSION_IS_RELEASE 0
+#define AMQP_VERSION_IS_RELEASE 1
/**
* \def AMQP_VERSION_CODE
@@ -328,16 +328,13 @@ char const *AMQP_CALL amqp_version(void);
/**
* \def AMQP_DEFAULT_MAX_CHANNELS
*
- * Default maximum number of channels (2047, RabbitMQ default limit of 2048,
- * minus 1 for channel 0). RabbitMQ set a default limit of 2048 channels per
- * connection in v3.7.5 to prevent broken clients from leaking too many
- * channels.
+ * Default maximum number of channels (0, no limit)
*
* \sa amqp_login(), amqp_login_with_properties()
*
* \since v0.4.0
*/
-#define AMQP_DEFAULT_MAX_CHANNELS 2047
+#define AMQP_DEFAULT_MAX_CHANNELS 0
/**
* \def AMQP_DEFAULT_HEARTBEAT
diff --git a/ext/librabbitmq/librabbitmq/amqp_api.c b/ext/librabbitmq/librabbitmq/amqp_api.c
new file mode 100644
index 000000000..28b238476
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_api.c
@@ -0,0 +1,394 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _MSC_VER
+/* MSVC complains about sprintf being deprecated in favor of sprintf_s */
+#define _CRT_SECURE_NO_WARNINGS
+/* MSVC complains about strdup being deprecated in favor of _strdup */
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#include "amqp_private.h"
+#include "amqp_time.h"
+#include
+#include
+#include
+#include
+#include
+
+#define ERROR_MASK (0x00FF)
+#define ERROR_CATEGORY_MASK (0xFF00)
+
+enum error_category_enum_ { EC_base = 0, EC_tcp = 1, EC_ssl = 2 };
+
+static const char *base_error_strings[] = {
+ /* AMQP_STATUS_OK 0x0 */
+ "operation completed successfully",
+ /* AMQP_STATUS_NO_MEMORY -0x0001 */
+ "could not allocate memory",
+ /* AMQP_STATUS_BAD_AQMP_DATA -0x0002 */
+ "invalid AMQP data",
+ /* AMQP_STATUS_UNKNOWN_CLASS -0x0003 */
+ "unknown AMQP class id",
+ /* AMQP_STATUS_UNKNOWN_METHOD -0x0004 */
+ "unknown AMQP method id",
+ /* AMQP_STATUS_HOSTNAME_RESOLUTION_FAILED -0x0005 */
+ "hostname lookup failed",
+ /* AMQP_STATUS_INCOMPATIBLE_AMQP_VERSION -0x0006 */
+ "incompatible AMQP version",
+ /* AMQP_STATUS_CONNECTION_CLOSED -0x0007 */
+ "connection closed unexpectedly",
+ /* AMQP_STATUS_BAD_AMQP_URL -0x0008 */
+ "could not parse AMQP URL",
+ /* AMQP_STATUS_SOCKET_ERROR -0x0009 */
+ "a socket error occurred",
+ /* AMQP_STATUS_INVALID_PARAMETER -0x000A */
+ "invalid parameter",
+ /* AMQP_STATUS_TABLE_TOO_BIG -0x000B */
+ "table too large for buffer",
+ /* AMQP_STATUS_WRONG_METHOD -0x000C */
+ "unexpected method received",
+ /* AMQP_STATUS_TIMEOUT -0x000D */
+ "request timed out",
+ /* AMQP_STATUS_TIMER_FAILED -0x000E */
+ "system timer has failed",
+ /* AMQP_STATUS_HEARTBEAT_TIMEOUT -0x000F */
+ "heartbeat timeout, connection closed",
+ /* AMQP_STATUS_UNEXPECTED STATE -0x0010 */
+ "unexpected protocol state",
+ /* AMQP_STATUS_SOCKET_CLOSED -0x0011 */
+ "socket is closed",
+ /* AMQP_STATUS_SOCKET_INUSE -0x0012 */
+ "socket already open",
+ /* AMQP_STATUS_BROKER_UNSUPPORTED_SASL_METHOD -0x00013 */
+ "unsupported sasl method requested",
+ /* AMQP_STATUS_UNSUPPORTED -0x0014 */
+ "parameter value is unsupported"};
+
+static const char *tcp_error_strings[] = {
+ /* AMQP_STATUS_TCP_ERROR -0x0100 */
+ "a socket error occurred",
+ /* AMQP_STATUS_TCP_SOCKETLIB_INIT_ERROR -0x0101 */
+ "socket library initialization failed"};
+
+static const char *ssl_error_strings[] = {
+ /* AMQP_STATUS_SSL_ERRO R -0x0200 */
+ "a SSL error occurred",
+ /* AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED -0x0201 */
+ "SSL hostname verification failed",
+ /* AMQP_STATUS_SSL_PEER_VERIFY_FAILED -0x0202 */
+ "SSL peer cert verification failed",
+ /* AMQP_STATUS_SSL_CONNECTION_FAILED -0x0203 */
+ "SSL handshake failed"};
+
+static const char *unknown_error_string = "(unknown error)";
+
+const char *amqp_error_string2(int code) {
+ const char *error_string;
+ size_t category = (((-code) & ERROR_CATEGORY_MASK) >> 8);
+ size_t error = (-code) & ERROR_MASK;
+
+ switch (category) {
+ case EC_base:
+ if (error < (sizeof(base_error_strings) / sizeof(char *))) {
+ error_string = base_error_strings[error];
+ } else {
+ error_string = unknown_error_string;
+ }
+ break;
+
+ case EC_tcp:
+ if (error < (sizeof(tcp_error_strings) / sizeof(char *))) {
+ error_string = tcp_error_strings[error];
+ } else {
+ error_string = unknown_error_string;
+ }
+ break;
+
+ case EC_ssl:
+ if (error < (sizeof(ssl_error_strings) / sizeof(char *))) {
+ error_string = ssl_error_strings[error];
+ } else {
+ error_string = unknown_error_string;
+ }
+
+ break;
+
+ default:
+ error_string = unknown_error_string;
+ break;
+ }
+
+ return error_string;
+}
+
+char *amqp_error_string(int code) {
+ /* Previously sometimes clients had to flip the sign on a return value from a
+ * function to get the correct error code. Now, all error codes are negative.
+ * To keep people's legacy code running correctly, we map all error codes to
+ * negative values.
+ *
+ * This is only done with this deprecated function.
+ */
+ if (code > 0) {
+ code = -code;
+ }
+ return strdup(amqp_error_string2(code));
+}
+
+void amqp_abort(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ abort();
+}
+
+const amqp_bytes_t amqp_empty_bytes = {0, NULL};
+const amqp_table_t amqp_empty_table = {0, NULL};
+const amqp_array_t amqp_empty_array = {0, NULL};
+
+int amqp_basic_publish(amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_bytes_t exchange, amqp_bytes_t routing_key,
+ amqp_boolean_t mandatory, amqp_boolean_t immediate,
+ amqp_basic_properties_t const *properties,
+ amqp_bytes_t body) {
+ amqp_frame_t f;
+ size_t body_offset;
+ size_t usable_body_payload_size =
+ state->frame_max - (HEADER_SIZE + FOOTER_SIZE);
+ int res;
+ int flagz;
+
+ amqp_basic_publish_t m;
+ amqp_basic_properties_t default_properties;
+
+ m.exchange = exchange;
+ m.routing_key = routing_key;
+ m.mandatory = mandatory;
+ m.immediate = immediate;
+ m.ticket = 0;
+
+ /* TODO(alanxz): this heartbeat check is happening in the wrong place, it
+ * should really be done in amqp_try_send/writev */
+ res = amqp_time_has_past(state->next_recv_heartbeat);
+ if (AMQP_STATUS_TIMER_FAILURE == res) {
+ return res;
+ } else if (AMQP_STATUS_TIMEOUT == res) {
+ res = amqp_try_recv(state);
+ if (AMQP_STATUS_TIMEOUT == res) {
+ return AMQP_STATUS_HEARTBEAT_TIMEOUT;
+ } else if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+ }
+
+ res = amqp_send_method_inner(state, channel, AMQP_BASIC_PUBLISH_METHOD, &m,
+ AMQP_SF_MORE, amqp_time_infinite());
+ if (res < 0) {
+ return res;
+ }
+
+ if (properties == NULL) {
+ memset(&default_properties, 0, sizeof(default_properties));
+ properties = &default_properties;
+ }
+
+ f.frame_type = AMQP_FRAME_HEADER;
+ f.channel = channel;
+ f.payload.properties.class_id = AMQP_BASIC_CLASS;
+ f.payload.properties.body_size = body.len;
+ f.payload.properties.decoded = (void *)properties;
+
+ if (body.len > 0) {
+ flagz = AMQP_SF_MORE;
+ } else {
+ flagz = AMQP_SF_NONE;
+ }
+ res = amqp_send_frame_inner(state, &f, flagz, amqp_time_infinite());
+ if (res < 0) {
+ return res;
+ }
+
+ body_offset = 0;
+ while (body_offset < body.len) {
+ size_t remaining = body.len - body_offset;
+
+ if (remaining == 0) {
+ break;
+ }
+
+ f.frame_type = AMQP_FRAME_BODY;
+ f.channel = channel;
+ f.payload.body_fragment.bytes = amqp_offset(body.bytes, body_offset);
+ if (remaining >= usable_body_payload_size) {
+ f.payload.body_fragment.len = usable_body_payload_size;
+ flagz = AMQP_SF_MORE;
+ } else {
+ f.payload.body_fragment.len = remaining;
+ flagz = AMQP_SF_NONE;
+ }
+
+ body_offset += f.payload.body_fragment.len;
+ res = amqp_send_frame_inner(state, &f, flagz, amqp_time_infinite());
+ if (res < 0) {
+ return res;
+ }
+ }
+
+ return AMQP_STATUS_OK;
+}
+
+amqp_rpc_reply_t amqp_channel_close(amqp_connection_state_t state,
+ amqp_channel_t channel, int code) {
+ char codestr[13];
+ amqp_method_number_t replies[2] = {AMQP_CHANNEL_CLOSE_OK_METHOD, 0};
+ amqp_channel_close_t req;
+
+ if (code < 0 || code > UINT16_MAX) {
+ return amqp_rpc_reply_error(AMQP_STATUS_INVALID_PARAMETER);
+ }
+
+ req.reply_code = (uint16_t)code;
+ req.reply_text.bytes = codestr;
+ req.reply_text.len = sprintf(codestr, "%d", code);
+ req.class_id = 0;
+ req.method_id = 0;
+
+ return amqp_simple_rpc(state, channel, AMQP_CHANNEL_CLOSE_METHOD, replies,
+ &req);
+}
+
+amqp_rpc_reply_t amqp_connection_close(amqp_connection_state_t state,
+ int code) {
+ char codestr[13];
+ amqp_method_number_t replies[2] = {AMQP_CONNECTION_CLOSE_OK_METHOD, 0};
+ amqp_channel_close_t req;
+
+ if (code < 0 || code > UINT16_MAX) {
+ return amqp_rpc_reply_error(AMQP_STATUS_INVALID_PARAMETER);
+ }
+
+ req.reply_code = (uint16_t)code;
+ req.reply_text.bytes = codestr;
+ req.reply_text.len = sprintf(codestr, "%d", code);
+ req.class_id = 0;
+ req.method_id = 0;
+
+ return amqp_simple_rpc(state, 0, AMQP_CONNECTION_CLOSE_METHOD, replies, &req);
+}
+
+int amqp_basic_ack(amqp_connection_state_t state, amqp_channel_t channel,
+ uint64_t delivery_tag, amqp_boolean_t multiple) {
+ amqp_basic_ack_t m;
+ m.delivery_tag = delivery_tag;
+ m.multiple = multiple;
+ return amqp_send_method(state, channel, AMQP_BASIC_ACK_METHOD, &m);
+}
+
+amqp_rpc_reply_t amqp_basic_get(amqp_connection_state_t state,
+ amqp_channel_t channel, amqp_bytes_t queue,
+ amqp_boolean_t no_ack) {
+ amqp_method_number_t replies[] = {AMQP_BASIC_GET_OK_METHOD,
+ AMQP_BASIC_GET_EMPTY_METHOD, 0};
+ amqp_basic_get_t req;
+ req.ticket = 0;
+ req.queue = queue;
+ req.no_ack = no_ack;
+
+ state->most_recent_api_result =
+ amqp_simple_rpc(state, channel, AMQP_BASIC_GET_METHOD, replies, &req);
+ return state->most_recent_api_result;
+}
+
+int amqp_basic_reject(amqp_connection_state_t state, amqp_channel_t channel,
+ uint64_t delivery_tag, amqp_boolean_t requeue) {
+ amqp_basic_reject_t req;
+ req.delivery_tag = delivery_tag;
+ req.requeue = requeue;
+ return amqp_send_method(state, channel, AMQP_BASIC_REJECT_METHOD, &req);
+}
+
+int amqp_basic_nack(amqp_connection_state_t state, amqp_channel_t channel,
+ uint64_t delivery_tag, amqp_boolean_t multiple,
+ amqp_boolean_t requeue) {
+ amqp_basic_nack_t req;
+ req.delivery_tag = delivery_tag;
+ req.multiple = multiple;
+ req.requeue = requeue;
+ return amqp_send_method(state, channel, AMQP_BASIC_NACK_METHOD, &req);
+}
+
+struct timeval *amqp_get_handshake_timeout(amqp_connection_state_t state) {
+ return state->handshake_timeout;
+}
+
+int amqp_set_handshake_timeout(amqp_connection_state_t state,
+ struct timeval *timeout) {
+ if (timeout) {
+ if (timeout->tv_sec < 0 || timeout->tv_usec < 0) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+ state->internal_handshake_timeout = *timeout;
+ state->handshake_timeout = &state->internal_handshake_timeout;
+ } else {
+ state->handshake_timeout = NULL;
+ }
+
+ return AMQP_STATUS_OK;
+}
+
+struct timeval *amqp_get_rpc_timeout(amqp_connection_state_t state) {
+ return state->rpc_timeout;
+}
+
+int amqp_set_rpc_timeout(amqp_connection_state_t state,
+ struct timeval *timeout) {
+ if (timeout) {
+ if (timeout->tv_sec < 0 || timeout->tv_usec < 0) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+ state->rpc_timeout = &state->internal_rpc_timeout;
+ *state->rpc_timeout = *timeout;
+ } else {
+ state->rpc_timeout = NULL;
+ }
+ return AMQP_STATUS_OK;
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_connection.c b/ext/librabbitmq/librabbitmq/amqp_connection.c
new file mode 100644
index 000000000..034b2e965
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_connection.c
@@ -0,0 +1,595 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2014
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "amqp_private.h"
+#include "amqp_tcp_socket.h"
+#include "amqp_time.h"
+#include
+#include
+#include
+#include
+#include
+
+#ifndef AMQP_INITIAL_FRAME_POOL_PAGE_SIZE
+#define AMQP_INITIAL_FRAME_POOL_PAGE_SIZE 65536
+#endif
+
+#ifndef AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE
+#define AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE 131072
+#endif
+
+#ifndef AMQP_DEFAULT_LOGIN_TIMEOUT_SEC
+#define AMQP_DEFAULT_LOGIN_TIMEOUT_SEC 12
+#endif
+
+#define ENFORCE_STATE(statevec, statenum) \
+ { \
+ amqp_connection_state_t _check_state = (statevec); \
+ amqp_connection_state_enum _wanted_state = (statenum); \
+ if (_check_state->state != _wanted_state) \
+ amqp_abort( \
+ "Programming error: invalid AMQP connection state: expected %d, " \
+ "got %d", \
+ _wanted_state, _check_state->state); \
+ }
+
+amqp_connection_state_t amqp_new_connection(void) {
+ int res;
+ amqp_connection_state_t state = (amqp_connection_state_t)calloc(
+ 1, sizeof(struct amqp_connection_state_t_));
+
+ if (state == NULL) {
+ return NULL;
+ }
+
+ res = amqp_tune_connection(state, 0, AMQP_INITIAL_FRAME_POOL_PAGE_SIZE, 0);
+ if (0 != res) {
+ goto out_nomem;
+ }
+
+ state->inbound_buffer.bytes = state->header_buffer;
+ state->inbound_buffer.len = sizeof(state->header_buffer);
+
+ state->state = CONNECTION_STATE_INITIAL;
+ /* the server protocol version response is 8 bytes, which conveniently
+ is also the minimum frame size */
+ state->target_size = 8;
+
+ state->sock_inbound_buffer.len = AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE;
+ state->sock_inbound_buffer.bytes =
+ malloc(AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE);
+ if (state->sock_inbound_buffer.bytes == NULL) {
+ goto out_nomem;
+ }
+
+ init_amqp_pool(&state->properties_pool, 512);
+
+ /* Use address of the internal_handshake_timeout object by default. */
+ state->internal_handshake_timeout.tv_sec = AMQP_DEFAULT_LOGIN_TIMEOUT_SEC;
+ state->internal_handshake_timeout.tv_usec = 0;
+ state->handshake_timeout = &state->internal_handshake_timeout;
+
+ return state;
+
+out_nomem:
+ free(state->sock_inbound_buffer.bytes);
+ free(state);
+ return NULL;
+}
+
+int amqp_get_sockfd(amqp_connection_state_t state) {
+ return state->socket ? amqp_socket_get_sockfd(state->socket) : -1;
+}
+
+void amqp_set_sockfd(amqp_connection_state_t state, int sockfd) {
+ amqp_socket_t *socket = amqp_tcp_socket_new(state);
+ if (!socket) {
+ amqp_abort("%s", strerror(errno));
+ }
+ amqp_tcp_socket_set_sockfd(socket, sockfd);
+}
+
+void amqp_set_socket(amqp_connection_state_t state, amqp_socket_t *socket) {
+ amqp_socket_delete(state->socket);
+ state->socket = socket;
+}
+
+amqp_socket_t *amqp_get_socket(amqp_connection_state_t state) {
+ return state->socket;
+}
+
+int amqp_tune_connection(amqp_connection_state_t state, int channel_max,
+ int frame_max, int heartbeat) {
+ void *newbuf;
+ int res;
+
+ ENFORCE_STATE(state, CONNECTION_STATE_IDLE);
+
+ state->channel_max = channel_max;
+ state->frame_max = frame_max;
+
+ state->heartbeat = heartbeat;
+ if (0 > state->heartbeat) {
+ state->heartbeat = 0;
+ }
+
+ res = amqp_time_s_from_now(&state->next_send_heartbeat,
+ amqp_heartbeat_send(state));
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+ res = amqp_time_s_from_now(&state->next_recv_heartbeat,
+ amqp_heartbeat_recv(state));
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+
+ state->outbound_buffer.len = frame_max;
+ newbuf = realloc(state->outbound_buffer.bytes, frame_max);
+ if (newbuf == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ state->outbound_buffer.bytes = newbuf;
+
+ return AMQP_STATUS_OK;
+}
+
+int amqp_get_channel_max(amqp_connection_state_t state) {
+ return state->channel_max;
+}
+
+int amqp_get_frame_max(amqp_connection_state_t state) {
+ return state->frame_max;
+}
+
+int amqp_get_heartbeat(amqp_connection_state_t state) {
+ return state->heartbeat;
+}
+
+int amqp_destroy_connection(amqp_connection_state_t state) {
+ int status = AMQP_STATUS_OK;
+ if (state) {
+ int i;
+ for (i = 0; i < POOL_TABLE_SIZE; ++i) {
+ amqp_pool_table_entry_t *entry = state->pool_table[i];
+ while (NULL != entry) {
+ amqp_pool_table_entry_t *todelete = entry;
+ empty_amqp_pool(&entry->pool);
+ entry = entry->next;
+ free(todelete);
+ }
+ }
+
+ free(state->outbound_buffer.bytes);
+ free(state->sock_inbound_buffer.bytes);
+ amqp_socket_delete(state->socket);
+ empty_amqp_pool(&state->properties_pool);
+ free(state);
+ }
+ return status;
+}
+
+static void return_to_idle(amqp_connection_state_t state) {
+ state->inbound_buffer.len = sizeof(state->header_buffer);
+ state->inbound_buffer.bytes = state->header_buffer;
+ state->inbound_offset = 0;
+ state->target_size = HEADER_SIZE;
+ state->state = CONNECTION_STATE_IDLE;
+}
+
+static size_t consume_data(amqp_connection_state_t state,
+ amqp_bytes_t *received_data) {
+ /* how much data is available and will fit? */
+ size_t bytes_consumed = state->target_size - state->inbound_offset;
+ if (received_data->len < bytes_consumed) {
+ bytes_consumed = received_data->len;
+ }
+
+ memcpy(amqp_offset(state->inbound_buffer.bytes, state->inbound_offset),
+ received_data->bytes, bytes_consumed);
+ state->inbound_offset += bytes_consumed;
+ received_data->bytes = amqp_offset(received_data->bytes, bytes_consumed);
+ received_data->len -= bytes_consumed;
+
+ return bytes_consumed;
+}
+
+int amqp_handle_input(amqp_connection_state_t state, amqp_bytes_t received_data,
+ amqp_frame_t *decoded_frame) {
+ size_t bytes_consumed;
+ void *raw_frame;
+
+ /* Returning frame_type of zero indicates either insufficient input,
+ or a complete, ignored frame was read. */
+ decoded_frame->frame_type = 0;
+
+ if (received_data.len == 0) {
+ return AMQP_STATUS_OK;
+ }
+
+ if (state->state == CONNECTION_STATE_IDLE) {
+ state->state = CONNECTION_STATE_HEADER;
+ }
+
+ bytes_consumed = consume_data(state, &received_data);
+
+ /* do we have target_size data yet? if not, return with the
+ expectation that more will arrive */
+ if (state->inbound_offset < state->target_size) {
+ return (int)bytes_consumed;
+ }
+
+ raw_frame = state->inbound_buffer.bytes;
+
+ switch (state->state) {
+ case CONNECTION_STATE_INITIAL:
+ /* check for a protocol header from the server */
+ if (memcmp(raw_frame, "AMQP", 4) == 0) {
+ decoded_frame->frame_type = AMQP_PSEUDOFRAME_PROTOCOL_HEADER;
+ decoded_frame->channel = 0;
+
+ decoded_frame->payload.protocol_header.transport_high =
+ amqp_d8(amqp_offset(raw_frame, 4));
+ decoded_frame->payload.protocol_header.transport_low =
+ amqp_d8(amqp_offset(raw_frame, 5));
+ decoded_frame->payload.protocol_header.protocol_version_major =
+ amqp_d8(amqp_offset(raw_frame, 6));
+ decoded_frame->payload.protocol_header.protocol_version_minor =
+ amqp_d8(amqp_offset(raw_frame, 7));
+
+ return_to_idle(state);
+ return (int)bytes_consumed;
+ }
+
+ /* it's not a protocol header; fall through to process it as a
+ regular frame header */
+
+ case CONNECTION_STATE_HEADER: {
+ amqp_channel_t channel;
+ amqp_pool_t *channel_pool;
+ /* frame length is 3 bytes in */
+ channel = amqp_d16(amqp_offset(raw_frame, 1));
+
+ state->target_size =
+ amqp_d32(amqp_offset(raw_frame, 3)) + HEADER_SIZE + FOOTER_SIZE;
+
+ if ((size_t)state->frame_max < state->target_size) {
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+
+ channel_pool = amqp_get_or_create_channel_pool(state, channel);
+ if (NULL == channel_pool) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ amqp_pool_alloc_bytes(channel_pool, state->target_size,
+ &state->inbound_buffer);
+ if (NULL == state->inbound_buffer.bytes) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ memcpy(state->inbound_buffer.bytes, state->header_buffer, HEADER_SIZE);
+ raw_frame = state->inbound_buffer.bytes;
+
+ state->state = CONNECTION_STATE_BODY;
+
+ bytes_consumed += consume_data(state, &received_data);
+
+ /* do we have target_size data yet? if not, return with the
+ expectation that more will arrive */
+ if (state->inbound_offset < state->target_size) {
+ return (int)bytes_consumed;
+ }
+ }
+ /* fall through to process body */
+
+ case CONNECTION_STATE_BODY: {
+ amqp_bytes_t encoded;
+ int res;
+ amqp_pool_t *channel_pool;
+
+ /* Check frame end marker (footer) */
+ if (amqp_d8(amqp_offset(raw_frame, state->target_size - 1)) !=
+ AMQP_FRAME_END) {
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+
+ decoded_frame->frame_type = amqp_d8(amqp_offset(raw_frame, 0));
+ decoded_frame->channel = amqp_d16(amqp_offset(raw_frame, 1));
+
+ channel_pool =
+ amqp_get_or_create_channel_pool(state, decoded_frame->channel);
+ if (NULL == channel_pool) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ switch (decoded_frame->frame_type) {
+ case AMQP_FRAME_METHOD:
+ decoded_frame->payload.method.id =
+ amqp_d32(amqp_offset(raw_frame, HEADER_SIZE));
+ encoded.bytes = amqp_offset(raw_frame, HEADER_SIZE + 4);
+ encoded.len = state->target_size - HEADER_SIZE - 4 - FOOTER_SIZE;
+
+ res = amqp_decode_method(decoded_frame->payload.method.id,
+ channel_pool, encoded,
+ &decoded_frame->payload.method.decoded);
+ if (res < 0) {
+ return res;
+ }
+
+ break;
+
+ case AMQP_FRAME_HEADER:
+ decoded_frame->payload.properties.class_id =
+ amqp_d16(amqp_offset(raw_frame, HEADER_SIZE));
+ /* unused 2-byte weight field goes here */
+ decoded_frame->payload.properties.body_size =
+ amqp_d64(amqp_offset(raw_frame, HEADER_SIZE + 4));
+ encoded.bytes = amqp_offset(raw_frame, HEADER_SIZE + 12);
+ encoded.len = state->target_size - HEADER_SIZE - 12 - FOOTER_SIZE;
+ decoded_frame->payload.properties.raw = encoded;
+
+ res = amqp_decode_properties(
+ decoded_frame->payload.properties.class_id, channel_pool, encoded,
+ &decoded_frame->payload.properties.decoded);
+ if (res < 0) {
+ return res;
+ }
+
+ break;
+
+ case AMQP_FRAME_BODY:
+ decoded_frame->payload.body_fragment.len =
+ state->target_size - HEADER_SIZE - FOOTER_SIZE;
+ decoded_frame->payload.body_fragment.bytes =
+ amqp_offset(raw_frame, HEADER_SIZE);
+ break;
+
+ case AMQP_FRAME_HEARTBEAT:
+ break;
+
+ default:
+ /* Ignore the frame */
+ decoded_frame->frame_type = 0;
+ break;
+ }
+
+ return_to_idle(state);
+ return (int)bytes_consumed;
+ }
+
+ default:
+ amqp_abort("Internal error: invalid amqp_connection_state_t->state %d",
+ state->state);
+ }
+}
+
+amqp_boolean_t amqp_release_buffers_ok(amqp_connection_state_t state) {
+ return (state->state == CONNECTION_STATE_IDLE);
+}
+
+void amqp_release_buffers(amqp_connection_state_t state) {
+ int i;
+ ENFORCE_STATE(state, CONNECTION_STATE_IDLE);
+
+ for (i = 0; i < POOL_TABLE_SIZE; ++i) {
+ amqp_pool_table_entry_t *entry = state->pool_table[i];
+
+ for (; NULL != entry; entry = entry->next) {
+ amqp_maybe_release_buffers_on_channel(state, entry->channel);
+ }
+ }
+}
+
+void amqp_maybe_release_buffers(amqp_connection_state_t state) {
+ if (amqp_release_buffers_ok(state)) {
+ amqp_release_buffers(state);
+ }
+}
+
+void amqp_maybe_release_buffers_on_channel(amqp_connection_state_t state,
+ amqp_channel_t channel) {
+ amqp_link_t *queued_link;
+ amqp_pool_t *pool;
+ if (CONNECTION_STATE_IDLE != state->state) {
+ return;
+ }
+
+ queued_link = state->first_queued_frame;
+
+ while (NULL != queued_link) {
+ amqp_frame_t *frame = queued_link->data;
+ if (channel == frame->channel) {
+ return;
+ }
+
+ queued_link = queued_link->next;
+ }
+
+ pool = amqp_get_channel_pool(state, channel);
+
+ if (pool != NULL) {
+ recycle_amqp_pool(pool);
+ }
+}
+
+static int amqp_frame_to_bytes(const amqp_frame_t *frame, amqp_bytes_t buffer,
+ amqp_bytes_t *encoded) {
+ void *out_frame = buffer.bytes;
+ size_t out_frame_len;
+ int res;
+
+ amqp_e8(frame->frame_type, amqp_offset(out_frame, 0));
+ amqp_e16(frame->channel, amqp_offset(out_frame, 1));
+
+ switch (frame->frame_type) {
+ case AMQP_FRAME_BODY: {
+ const amqp_bytes_t *body = &frame->payload.body_fragment;
+
+ memcpy(amqp_offset(out_frame, HEADER_SIZE), body->bytes, body->len);
+
+ out_frame_len = body->len;
+ break;
+ }
+ case AMQP_FRAME_METHOD: {
+ amqp_bytes_t method_encoded;
+
+ amqp_e32(frame->payload.method.id, amqp_offset(out_frame, HEADER_SIZE));
+
+ method_encoded.bytes = amqp_offset(out_frame, HEADER_SIZE + 4);
+ method_encoded.len = buffer.len - HEADER_SIZE - 4 - FOOTER_SIZE;
+
+ res = amqp_encode_method(frame->payload.method.id,
+ frame->payload.method.decoded, method_encoded);
+ if (res < 0) {
+ return res;
+ }
+
+ out_frame_len = res + 4;
+ break;
+ }
+
+ case AMQP_FRAME_HEADER: {
+ amqp_bytes_t properties_encoded;
+
+ amqp_e16(frame->payload.properties.class_id,
+ amqp_offset(out_frame, HEADER_SIZE));
+ amqp_e16(0, amqp_offset(out_frame, HEADER_SIZE + 2)); /* "weight" */
+ amqp_e64(frame->payload.properties.body_size,
+ amqp_offset(out_frame, HEADER_SIZE + 4));
+
+ properties_encoded.bytes = amqp_offset(out_frame, HEADER_SIZE + 12);
+ properties_encoded.len = buffer.len - HEADER_SIZE - 12 - FOOTER_SIZE;
+
+ res = amqp_encode_properties(frame->payload.properties.class_id,
+ frame->payload.properties.decoded,
+ properties_encoded);
+ if (res < 0) {
+ return res;
+ }
+
+ out_frame_len = res + 12;
+ break;
+ }
+
+ case AMQP_FRAME_HEARTBEAT:
+ out_frame_len = 0;
+ break;
+
+ default:
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+
+ amqp_e32((uint32_t)out_frame_len, amqp_offset(out_frame, 3));
+ amqp_e8(AMQP_FRAME_END, amqp_offset(out_frame, HEADER_SIZE + out_frame_len));
+
+ encoded->bytes = out_frame;
+ encoded->len = out_frame_len + HEADER_SIZE + FOOTER_SIZE;
+
+ return AMQP_STATUS_OK;
+}
+
+int amqp_send_frame(amqp_connection_state_t state, const amqp_frame_t *frame) {
+ return amqp_send_frame_inner(state, frame, AMQP_SF_NONE,
+ amqp_time_infinite());
+}
+
+int amqp_send_frame_inner(amqp_connection_state_t state,
+ const amqp_frame_t *frame, int flags,
+ amqp_time_t deadline) {
+ int res;
+ ssize_t sent;
+ amqp_bytes_t encoded;
+ amqp_time_t next_timeout;
+
+ /* TODO: if the AMQP_SF_MORE socket optimization can be shown to work
+ * correctly, then this could be un-done so that body-frames are sent as 3
+ * send calls, getting rid of the copy of the body content, some testing
+ * would need to be done to see if this would actually a win for performance.
+ * */
+ res = amqp_frame_to_bytes(frame, state->outbound_buffer, &encoded);
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+
+start_send:
+
+ next_timeout = amqp_time_first(deadline, state->next_recv_heartbeat);
+
+ sent = amqp_try_send(state, encoded.bytes, encoded.len, next_timeout, flags);
+ if (0 > sent) {
+ return (int)sent;
+ }
+
+ /* A partial send has occurred, because of a heartbeat timeout (so try recv
+ * something) or common timeout (so return AMQP_STATUS_TIMEOUT) */
+ if ((ssize_t)encoded.len != sent) {
+ if (amqp_time_equal(next_timeout, deadline)) {
+ /* timeout of method was received, so return from method*/
+ return AMQP_STATUS_TIMEOUT;
+ }
+
+ res = amqp_try_recv(state);
+
+ if (AMQP_STATUS_TIMEOUT == res) {
+ return AMQP_STATUS_HEARTBEAT_TIMEOUT;
+ } else if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+
+ encoded.bytes = (uint8_t *)encoded.bytes + sent;
+ encoded.len -= sent;
+ goto start_send;
+ }
+
+ res = amqp_time_s_from_now(&state->next_send_heartbeat,
+ amqp_heartbeat_send(state));
+ return res;
+}
+
+amqp_table_t *amqp_get_server_properties(amqp_connection_state_t state) {
+ return &state->server_properties;
+}
+
+amqp_table_t *amqp_get_client_properties(amqp_connection_state_t state) {
+ return &state->client_properties;
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_consumer.c b/ext/librabbitmq/librabbitmq/amqp_consumer.c
new file mode 100644
index 000000000..bb9095f92
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_consumer.c
@@ -0,0 +1,307 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2013-2014
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+#include "amqp.h"
+#include "amqp_private.h"
+#include "amqp_socket.h"
+
+#include
+#include
+
+static int amqp_basic_properties_clone(amqp_basic_properties_t *original,
+ amqp_basic_properties_t *clone,
+ amqp_pool_t *pool) {
+ memset(clone, 0, sizeof(*clone));
+ clone->_flags = original->_flags;
+
+#define CLONE_BYTES_POOL(original, clone, pool) \
+ if (0 == original.len) { \
+ clone = amqp_empty_bytes; \
+ } else { \
+ amqp_pool_alloc_bytes(pool, original.len, &clone); \
+ if (NULL == clone.bytes) { \
+ return AMQP_STATUS_NO_MEMORY; \
+ } \
+ memcpy(clone.bytes, original.bytes, clone.len); \
+ }
+
+ if (clone->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
+ CLONE_BYTES_POOL(original->content_type, clone->content_type, pool)
+ }
+
+ if (clone->_flags & AMQP_BASIC_CONTENT_ENCODING_FLAG) {
+ CLONE_BYTES_POOL(original->content_encoding, clone->content_encoding, pool)
+ }
+
+ if (clone->_flags & AMQP_BASIC_HEADERS_FLAG) {
+ int res = amqp_table_clone(&original->headers, &clone->headers, pool);
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+ }
+
+ if (clone->_flags & AMQP_BASIC_DELIVERY_MODE_FLAG) {
+ clone->delivery_mode = original->delivery_mode;
+ }
+
+ if (clone->_flags & AMQP_BASIC_PRIORITY_FLAG) {
+ clone->priority = original->priority;
+ }
+
+ if (clone->_flags & AMQP_BASIC_CORRELATION_ID_FLAG) {
+ CLONE_BYTES_POOL(original->correlation_id, clone->correlation_id, pool)
+ }
+
+ if (clone->_flags & AMQP_BASIC_REPLY_TO_FLAG) {
+ CLONE_BYTES_POOL(original->reply_to, clone->reply_to, pool)
+ }
+
+ if (clone->_flags & AMQP_BASIC_EXPIRATION_FLAG) {
+ CLONE_BYTES_POOL(original->expiration, clone->expiration, pool)
+ }
+
+ if (clone->_flags & AMQP_BASIC_MESSAGE_ID_FLAG) {
+ CLONE_BYTES_POOL(original->message_id, clone->message_id, pool)
+ }
+
+ if (clone->_flags & AMQP_BASIC_TIMESTAMP_FLAG) {
+ clone->timestamp = original->timestamp;
+ }
+
+ if (clone->_flags & AMQP_BASIC_TYPE_FLAG) {
+ CLONE_BYTES_POOL(original->type, clone->type, pool)
+ }
+
+ if (clone->_flags & AMQP_BASIC_USER_ID_FLAG) {
+ CLONE_BYTES_POOL(original->user_id, clone->user_id, pool)
+ }
+
+ if (clone->_flags & AMQP_BASIC_APP_ID_FLAG) {
+ CLONE_BYTES_POOL(original->app_id, clone->app_id, pool)
+ }
+
+ if (clone->_flags & AMQP_BASIC_CLUSTER_ID_FLAG) {
+ CLONE_BYTES_POOL(original->cluster_id, clone->cluster_id, pool)
+ }
+
+ return AMQP_STATUS_OK;
+#undef CLONE_BYTES_POOL
+}
+
+void amqp_destroy_message(amqp_message_t *message) {
+ empty_amqp_pool(&message->pool);
+ amqp_bytes_free(message->body);
+}
+
+void amqp_destroy_envelope(amqp_envelope_t *envelope) {
+ amqp_destroy_message(&envelope->message);
+ amqp_bytes_free(envelope->routing_key);
+ amqp_bytes_free(envelope->exchange);
+ amqp_bytes_free(envelope->consumer_tag);
+}
+
+static int amqp_bytes_malloc_dup_failed(amqp_bytes_t bytes) {
+ if (bytes.len != 0 && bytes.bytes == NULL) {
+ return 1;
+ }
+ return 0;
+}
+
+amqp_rpc_reply_t amqp_consume_message(amqp_connection_state_t state,
+ amqp_envelope_t *envelope,
+ struct timeval *timeout,
+ AMQP_UNUSED int flags) {
+ int res;
+ amqp_frame_t frame;
+ amqp_basic_deliver_t *delivery_method;
+ amqp_rpc_reply_t ret;
+
+ memset(&ret, 0, sizeof(ret));
+ memset(envelope, 0, sizeof(*envelope));
+
+ res = amqp_simple_wait_frame_noblock(state, &frame, timeout);
+ if (AMQP_STATUS_OK != res) {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = res;
+ goto error_out1;
+ }
+
+ if (AMQP_FRAME_METHOD != frame.frame_type ||
+ AMQP_BASIC_DELIVER_METHOD != frame.payload.method.id) {
+ amqp_put_back_frame(state, &frame);
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = AMQP_STATUS_UNEXPECTED_STATE;
+ goto error_out1;
+ }
+
+ delivery_method = frame.payload.method.decoded;
+
+ envelope->channel = frame.channel;
+ envelope->consumer_tag = amqp_bytes_malloc_dup(delivery_method->consumer_tag);
+ envelope->delivery_tag = delivery_method->delivery_tag;
+ envelope->redelivered = delivery_method->redelivered;
+ envelope->exchange = amqp_bytes_malloc_dup(delivery_method->exchange);
+ envelope->routing_key = amqp_bytes_malloc_dup(delivery_method->routing_key);
+
+ if (amqp_bytes_malloc_dup_failed(envelope->consumer_tag) ||
+ amqp_bytes_malloc_dup_failed(envelope->exchange) ||
+ amqp_bytes_malloc_dup_failed(envelope->routing_key)) {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = AMQP_STATUS_NO_MEMORY;
+ goto error_out2;
+ }
+
+ ret = amqp_read_message(state, envelope->channel, &envelope->message, 0);
+ if (AMQP_RESPONSE_NORMAL != ret.reply_type) {
+ goto error_out2;
+ }
+
+ ret.reply_type = AMQP_RESPONSE_NORMAL;
+ return ret;
+
+error_out2:
+ amqp_bytes_free(envelope->routing_key);
+ amqp_bytes_free(envelope->exchange);
+ amqp_bytes_free(envelope->consumer_tag);
+error_out1:
+ return ret;
+}
+
+amqp_rpc_reply_t amqp_read_message(amqp_connection_state_t state,
+ amqp_channel_t channel,
+ amqp_message_t *message,
+ AMQP_UNUSED int flags) {
+ amqp_frame_t frame;
+ amqp_rpc_reply_t ret;
+
+ size_t body_read;
+ char *body_read_ptr;
+ int res;
+
+ memset(&ret, 0, sizeof(ret));
+ memset(message, 0, sizeof(*message));
+
+ res = amqp_simple_wait_frame_on_channel(state, channel, &frame);
+ if (AMQP_STATUS_OK != res) {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = res;
+
+ goto error_out1;
+ }
+
+ if (AMQP_FRAME_HEADER != frame.frame_type) {
+ if (AMQP_FRAME_METHOD == frame.frame_type &&
+ (AMQP_CHANNEL_CLOSE_METHOD == frame.payload.method.id ||
+ AMQP_CONNECTION_CLOSE_METHOD == frame.payload.method.id)) {
+
+ ret.reply_type = AMQP_RESPONSE_SERVER_EXCEPTION;
+ ret.reply = frame.payload.method;
+
+ } else {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = AMQP_STATUS_UNEXPECTED_STATE;
+
+ amqp_put_back_frame(state, &frame);
+ }
+ goto error_out1;
+ }
+
+ init_amqp_pool(&message->pool, 4096);
+ res = amqp_basic_properties_clone(frame.payload.properties.decoded,
+ &message->properties, &message->pool);
+
+ if (AMQP_STATUS_OK != res) {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = res;
+ goto error_out3;
+ }
+
+ if (0 == frame.payload.properties.body_size) {
+ message->body = amqp_empty_bytes;
+ } else {
+ if (SIZE_MAX < frame.payload.properties.body_size) {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = AMQP_STATUS_NO_MEMORY;
+ goto error_out1;
+ }
+ message->body =
+ amqp_bytes_malloc((size_t)frame.payload.properties.body_size);
+ if (NULL == message->body.bytes) {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = AMQP_STATUS_NO_MEMORY;
+ goto error_out1;
+ }
+ }
+
+ body_read = 0;
+ body_read_ptr = message->body.bytes;
+
+ while (body_read < message->body.len) {
+ res = amqp_simple_wait_frame_on_channel(state, channel, &frame);
+ if (AMQP_STATUS_OK != res) {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = res;
+ goto error_out2;
+ }
+ if (AMQP_FRAME_BODY != frame.frame_type) {
+ if (AMQP_FRAME_METHOD == frame.frame_type &&
+ (AMQP_CHANNEL_CLOSE_METHOD == frame.payload.method.id ||
+ AMQP_CONNECTION_CLOSE_METHOD == frame.payload.method.id)) {
+
+ ret.reply_type = AMQP_RESPONSE_SERVER_EXCEPTION;
+ ret.reply = frame.payload.method;
+ } else {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ goto error_out2;
+ }
+
+ if (body_read + frame.payload.body_fragment.len > message->body.len) {
+ ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ ret.library_error = AMQP_STATUS_BAD_AMQP_DATA;
+ goto error_out2;
+ }
+
+ memcpy(body_read_ptr, frame.payload.body_fragment.bytes,
+ frame.payload.body_fragment.len);
+
+ body_read += frame.payload.body_fragment.len;
+ body_read_ptr += frame.payload.body_fragment.len;
+ }
+
+ ret.reply_type = AMQP_RESPONSE_NORMAL;
+ return ret;
+
+error_out2:
+ amqp_bytes_free(message->body);
+error_out3:
+ empty_amqp_pool(&message->pool);
+error_out1:
+ return ret;
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_framing.c b/ext/librabbitmq/librabbitmq/amqp_framing.c
new file mode 100644
index 000000000..bdeb01cd4
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_framing.c
@@ -0,0 +1,2876 @@
+/* Generated code. Do not edit. Edit and re-run codegen.py instead.
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "amqp_private.h"
+#include
+#include
+#include
+#include
+
+char const *amqp_constant_name(int constantNumber) {
+ switch (constantNumber) {
+ case AMQP_FRAME_METHOD:
+ return "AMQP_FRAME_METHOD";
+ case AMQP_FRAME_HEADER:
+ return "AMQP_FRAME_HEADER";
+ case AMQP_FRAME_BODY:
+ return "AMQP_FRAME_BODY";
+ case AMQP_FRAME_HEARTBEAT:
+ return "AMQP_FRAME_HEARTBEAT";
+ case AMQP_FRAME_MIN_SIZE:
+ return "AMQP_FRAME_MIN_SIZE";
+ case AMQP_FRAME_END:
+ return "AMQP_FRAME_END";
+ case AMQP_REPLY_SUCCESS:
+ return "AMQP_REPLY_SUCCESS";
+ case AMQP_CONTENT_TOO_LARGE:
+ return "AMQP_CONTENT_TOO_LARGE";
+ case AMQP_NO_ROUTE:
+ return "AMQP_NO_ROUTE";
+ case AMQP_NO_CONSUMERS:
+ return "AMQP_NO_CONSUMERS";
+ case AMQP_ACCESS_REFUSED:
+ return "AMQP_ACCESS_REFUSED";
+ case AMQP_NOT_FOUND:
+ return "AMQP_NOT_FOUND";
+ case AMQP_RESOURCE_LOCKED:
+ return "AMQP_RESOURCE_LOCKED";
+ case AMQP_PRECONDITION_FAILED:
+ return "AMQP_PRECONDITION_FAILED";
+ case AMQP_CONNECTION_FORCED:
+ return "AMQP_CONNECTION_FORCED";
+ case AMQP_INVALID_PATH:
+ return "AMQP_INVALID_PATH";
+ case AMQP_FRAME_ERROR:
+ return "AMQP_FRAME_ERROR";
+ case AMQP_SYNTAX_ERROR:
+ return "AMQP_SYNTAX_ERROR";
+ case AMQP_COMMAND_INVALID:
+ return "AMQP_COMMAND_INVALID";
+ case AMQP_CHANNEL_ERROR:
+ return "AMQP_CHANNEL_ERROR";
+ case AMQP_UNEXPECTED_FRAME:
+ return "AMQP_UNEXPECTED_FRAME";
+ case AMQP_RESOURCE_ERROR:
+ return "AMQP_RESOURCE_ERROR";
+ case AMQP_NOT_ALLOWED:
+ return "AMQP_NOT_ALLOWED";
+ case AMQP_NOT_IMPLEMENTED:
+ return "AMQP_NOT_IMPLEMENTED";
+ case AMQP_INTERNAL_ERROR:
+ return "AMQP_INTERNAL_ERROR";
+ default:
+ return "(unknown)";
+ }
+}
+
+amqp_boolean_t amqp_constant_is_hard_error(int constantNumber) {
+ switch (constantNumber) {
+ case AMQP_CONNECTION_FORCED:
+ return 1;
+ case AMQP_INVALID_PATH:
+ return 1;
+ case AMQP_FRAME_ERROR:
+ return 1;
+ case AMQP_SYNTAX_ERROR:
+ return 1;
+ case AMQP_COMMAND_INVALID:
+ return 1;
+ case AMQP_CHANNEL_ERROR:
+ return 1;
+ case AMQP_UNEXPECTED_FRAME:
+ return 1;
+ case AMQP_RESOURCE_ERROR:
+ return 1;
+ case AMQP_NOT_ALLOWED:
+ return 1;
+ case AMQP_NOT_IMPLEMENTED:
+ return 1;
+ case AMQP_INTERNAL_ERROR:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+char const *amqp_method_name(amqp_method_number_t methodNumber) {
+ switch (methodNumber) {
+ case AMQP_CONNECTION_START_METHOD:
+ return "AMQP_CONNECTION_START_METHOD";
+ case AMQP_CONNECTION_START_OK_METHOD:
+ return "AMQP_CONNECTION_START_OK_METHOD";
+ case AMQP_CONNECTION_SECURE_METHOD:
+ return "AMQP_CONNECTION_SECURE_METHOD";
+ case AMQP_CONNECTION_SECURE_OK_METHOD:
+ return "AMQP_CONNECTION_SECURE_OK_METHOD";
+ case AMQP_CONNECTION_TUNE_METHOD:
+ return "AMQP_CONNECTION_TUNE_METHOD";
+ case AMQP_CONNECTION_TUNE_OK_METHOD:
+ return "AMQP_CONNECTION_TUNE_OK_METHOD";
+ case AMQP_CONNECTION_OPEN_METHOD:
+ return "AMQP_CONNECTION_OPEN_METHOD";
+ case AMQP_CONNECTION_OPEN_OK_METHOD:
+ return "AMQP_CONNECTION_OPEN_OK_METHOD";
+ case AMQP_CONNECTION_CLOSE_METHOD:
+ return "AMQP_CONNECTION_CLOSE_METHOD";
+ case AMQP_CONNECTION_CLOSE_OK_METHOD:
+ return "AMQP_CONNECTION_CLOSE_OK_METHOD";
+ case AMQP_CONNECTION_BLOCKED_METHOD:
+ return "AMQP_CONNECTION_BLOCKED_METHOD";
+ case AMQP_CONNECTION_UNBLOCKED_METHOD:
+ return "AMQP_CONNECTION_UNBLOCKED_METHOD";
+ case AMQP_CHANNEL_OPEN_METHOD:
+ return "AMQP_CHANNEL_OPEN_METHOD";
+ case AMQP_CHANNEL_OPEN_OK_METHOD:
+ return "AMQP_CHANNEL_OPEN_OK_METHOD";
+ case AMQP_CHANNEL_FLOW_METHOD:
+ return "AMQP_CHANNEL_FLOW_METHOD";
+ case AMQP_CHANNEL_FLOW_OK_METHOD:
+ return "AMQP_CHANNEL_FLOW_OK_METHOD";
+ case AMQP_CHANNEL_CLOSE_METHOD:
+ return "AMQP_CHANNEL_CLOSE_METHOD";
+ case AMQP_CHANNEL_CLOSE_OK_METHOD:
+ return "AMQP_CHANNEL_CLOSE_OK_METHOD";
+ case AMQP_ACCESS_REQUEST_METHOD:
+ return "AMQP_ACCESS_REQUEST_METHOD";
+ case AMQP_ACCESS_REQUEST_OK_METHOD:
+ return "AMQP_ACCESS_REQUEST_OK_METHOD";
+ case AMQP_EXCHANGE_DECLARE_METHOD:
+ return "AMQP_EXCHANGE_DECLARE_METHOD";
+ case AMQP_EXCHANGE_DECLARE_OK_METHOD:
+ return "AMQP_EXCHANGE_DECLARE_OK_METHOD";
+ case AMQP_EXCHANGE_DELETE_METHOD:
+ return "AMQP_EXCHANGE_DELETE_METHOD";
+ case AMQP_EXCHANGE_DELETE_OK_METHOD:
+ return "AMQP_EXCHANGE_DELETE_OK_METHOD";
+ case AMQP_EXCHANGE_BIND_METHOD:
+ return "AMQP_EXCHANGE_BIND_METHOD";
+ case AMQP_EXCHANGE_BIND_OK_METHOD:
+ return "AMQP_EXCHANGE_BIND_OK_METHOD";
+ case AMQP_EXCHANGE_UNBIND_METHOD:
+ return "AMQP_EXCHANGE_UNBIND_METHOD";
+ case AMQP_EXCHANGE_UNBIND_OK_METHOD:
+ return "AMQP_EXCHANGE_UNBIND_OK_METHOD";
+ case AMQP_QUEUE_DECLARE_METHOD:
+ return "AMQP_QUEUE_DECLARE_METHOD";
+ case AMQP_QUEUE_DECLARE_OK_METHOD:
+ return "AMQP_QUEUE_DECLARE_OK_METHOD";
+ case AMQP_QUEUE_BIND_METHOD:
+ return "AMQP_QUEUE_BIND_METHOD";
+ case AMQP_QUEUE_BIND_OK_METHOD:
+ return "AMQP_QUEUE_BIND_OK_METHOD";
+ case AMQP_QUEUE_PURGE_METHOD:
+ return "AMQP_QUEUE_PURGE_METHOD";
+ case AMQP_QUEUE_PURGE_OK_METHOD:
+ return "AMQP_QUEUE_PURGE_OK_METHOD";
+ case AMQP_QUEUE_DELETE_METHOD:
+ return "AMQP_QUEUE_DELETE_METHOD";
+ case AMQP_QUEUE_DELETE_OK_METHOD:
+ return "AMQP_QUEUE_DELETE_OK_METHOD";
+ case AMQP_QUEUE_UNBIND_METHOD:
+ return "AMQP_QUEUE_UNBIND_METHOD";
+ case AMQP_QUEUE_UNBIND_OK_METHOD:
+ return "AMQP_QUEUE_UNBIND_OK_METHOD";
+ case AMQP_BASIC_QOS_METHOD:
+ return "AMQP_BASIC_QOS_METHOD";
+ case AMQP_BASIC_QOS_OK_METHOD:
+ return "AMQP_BASIC_QOS_OK_METHOD";
+ case AMQP_BASIC_CONSUME_METHOD:
+ return "AMQP_BASIC_CONSUME_METHOD";
+ case AMQP_BASIC_CONSUME_OK_METHOD:
+ return "AMQP_BASIC_CONSUME_OK_METHOD";
+ case AMQP_BASIC_CANCEL_METHOD:
+ return "AMQP_BASIC_CANCEL_METHOD";
+ case AMQP_BASIC_CANCEL_OK_METHOD:
+ return "AMQP_BASIC_CANCEL_OK_METHOD";
+ case AMQP_BASIC_PUBLISH_METHOD:
+ return "AMQP_BASIC_PUBLISH_METHOD";
+ case AMQP_BASIC_RETURN_METHOD:
+ return "AMQP_BASIC_RETURN_METHOD";
+ case AMQP_BASIC_DELIVER_METHOD:
+ return "AMQP_BASIC_DELIVER_METHOD";
+ case AMQP_BASIC_GET_METHOD:
+ return "AMQP_BASIC_GET_METHOD";
+ case AMQP_BASIC_GET_OK_METHOD:
+ return "AMQP_BASIC_GET_OK_METHOD";
+ case AMQP_BASIC_GET_EMPTY_METHOD:
+ return "AMQP_BASIC_GET_EMPTY_METHOD";
+ case AMQP_BASIC_ACK_METHOD:
+ return "AMQP_BASIC_ACK_METHOD";
+ case AMQP_BASIC_REJECT_METHOD:
+ return "AMQP_BASIC_REJECT_METHOD";
+ case AMQP_BASIC_RECOVER_ASYNC_METHOD:
+ return "AMQP_BASIC_RECOVER_ASYNC_METHOD";
+ case AMQP_BASIC_RECOVER_METHOD:
+ return "AMQP_BASIC_RECOVER_METHOD";
+ case AMQP_BASIC_RECOVER_OK_METHOD:
+ return "AMQP_BASIC_RECOVER_OK_METHOD";
+ case AMQP_BASIC_NACK_METHOD:
+ return "AMQP_BASIC_NACK_METHOD";
+ case AMQP_TX_SELECT_METHOD:
+ return "AMQP_TX_SELECT_METHOD";
+ case AMQP_TX_SELECT_OK_METHOD:
+ return "AMQP_TX_SELECT_OK_METHOD";
+ case AMQP_TX_COMMIT_METHOD:
+ return "AMQP_TX_COMMIT_METHOD";
+ case AMQP_TX_COMMIT_OK_METHOD:
+ return "AMQP_TX_COMMIT_OK_METHOD";
+ case AMQP_TX_ROLLBACK_METHOD:
+ return "AMQP_TX_ROLLBACK_METHOD";
+ case AMQP_TX_ROLLBACK_OK_METHOD:
+ return "AMQP_TX_ROLLBACK_OK_METHOD";
+ case AMQP_CONFIRM_SELECT_METHOD:
+ return "AMQP_CONFIRM_SELECT_METHOD";
+ case AMQP_CONFIRM_SELECT_OK_METHOD:
+ return "AMQP_CONFIRM_SELECT_OK_METHOD";
+ default:
+ return NULL;
+ }
+}
+
+amqp_boolean_t amqp_method_has_content(amqp_method_number_t methodNumber) {
+ switch (methodNumber) {
+ case AMQP_BASIC_PUBLISH_METHOD:
+ return 1;
+ case AMQP_BASIC_RETURN_METHOD:
+ return 1;
+ case AMQP_BASIC_DELIVER_METHOD:
+ return 1;
+ case AMQP_BASIC_GET_OK_METHOD:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int amqp_decode_method(amqp_method_number_t methodNumber, amqp_pool_t *pool,
+ amqp_bytes_t encoded, void **decoded) {
+ size_t offset = 0;
+ uint8_t bit_buffer;
+
+ switch (methodNumber) {
+ case AMQP_CONNECTION_START_METHOD: {
+ amqp_connection_start_t *m = (amqp_connection_start_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_start_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_8(encoded, &offset, &m->version_major))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_8(encoded, &offset, &m->version_minor))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ int res =
+ amqp_decode_table(encoded, pool, &(m->server_properties), &offset);
+ if (res < 0) return res;
+ }
+ {
+ uint32_t len;
+ if (!amqp_decode_32(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->mechanisms, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint32_t len;
+ if (!amqp_decode_32(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->locales, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_START_OK_METHOD: {
+ amqp_connection_start_ok_t *m =
+ (amqp_connection_start_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_start_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ int res =
+ amqp_decode_table(encoded, pool, &(m->client_properties), &offset);
+ if (res < 0) return res;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->mechanism, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint32_t len;
+ if (!amqp_decode_32(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->response, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->locale, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_SECURE_METHOD: {
+ amqp_connection_secure_t *m = (amqp_connection_secure_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_secure_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint32_t len;
+ if (!amqp_decode_32(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->challenge, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_SECURE_OK_METHOD: {
+ amqp_connection_secure_ok_t *m =
+ (amqp_connection_secure_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_secure_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint32_t len;
+ if (!amqp_decode_32(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->response, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_TUNE_METHOD: {
+ amqp_connection_tune_t *m = (amqp_connection_tune_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_tune_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->channel_max))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_32(encoded, &offset, &m->frame_max))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_16(encoded, &offset, &m->heartbeat))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_TUNE_OK_METHOD: {
+ amqp_connection_tune_ok_t *m =
+ (amqp_connection_tune_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_tune_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->channel_max))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_32(encoded, &offset, &m->frame_max))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_16(encoded, &offset, &m->heartbeat))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_OPEN_METHOD: {
+ amqp_connection_open_t *m = (amqp_connection_open_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_open_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->virtual_host, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->capabilities, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->insist = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_OPEN_OK_METHOD: {
+ amqp_connection_open_ok_t *m =
+ (amqp_connection_open_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_open_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->known_hosts, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_CLOSE_METHOD: {
+ amqp_connection_close_t *m = (amqp_connection_close_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_close_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->reply_code))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->reply_text, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->class_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_16(encoded, &offset, &m->method_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_CLOSE_OK_METHOD: {
+ amqp_connection_close_ok_t *m =
+ (amqp_connection_close_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_close_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_BLOCKED_METHOD: {
+ amqp_connection_blocked_t *m =
+ (amqp_connection_blocked_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_blocked_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->reason, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONNECTION_UNBLOCKED_METHOD: {
+ amqp_connection_unblocked_t *m =
+ (amqp_connection_unblocked_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_unblocked_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CHANNEL_OPEN_METHOD: {
+ amqp_channel_open_t *m = (amqp_channel_open_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_channel_open_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->out_of_band, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CHANNEL_OPEN_OK_METHOD: {
+ amqp_channel_open_ok_t *m = (amqp_channel_open_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_channel_open_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint32_t len;
+ if (!amqp_decode_32(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->channel_id, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CHANNEL_FLOW_METHOD: {
+ amqp_channel_flow_t *m = (amqp_channel_flow_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_channel_flow_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->active = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CHANNEL_FLOW_OK_METHOD: {
+ amqp_channel_flow_ok_t *m = (amqp_channel_flow_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_channel_flow_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->active = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CHANNEL_CLOSE_METHOD: {
+ amqp_channel_close_t *m = (amqp_channel_close_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_channel_close_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->reply_code))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->reply_text, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->class_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_16(encoded, &offset, &m->method_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CHANNEL_CLOSE_OK_METHOD: {
+ amqp_channel_close_ok_t *m = (amqp_channel_close_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_channel_close_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_ACCESS_REQUEST_METHOD: {
+ amqp_access_request_t *m = (amqp_access_request_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_access_request_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->realm, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->exclusive = (bit_buffer & (1 << 0)) ? 1 : 0;
+ m->passive = (bit_buffer & (1 << 1)) ? 1 : 0;
+ m->active = (bit_buffer & (1 << 2)) ? 1 : 0;
+ m->write = (bit_buffer & (1 << 3)) ? 1 : 0;
+ m->read = (bit_buffer & (1 << 4)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_ACCESS_REQUEST_OK_METHOD: {
+ amqp_access_request_ok_t *m = (amqp_access_request_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_access_request_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_EXCHANGE_DECLARE_METHOD: {
+ amqp_exchange_declare_t *m = (amqp_exchange_declare_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_exchange_declare_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->exchange, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->type, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->passive = (bit_buffer & (1 << 0)) ? 1 : 0;
+ m->durable = (bit_buffer & (1 << 1)) ? 1 : 0;
+ m->auto_delete = (bit_buffer & (1 << 2)) ? 1 : 0;
+ m->internal = (bit_buffer & (1 << 3)) ? 1 : 0;
+ m->nowait = (bit_buffer & (1 << 4)) ? 1 : 0;
+ {
+ int res = amqp_decode_table(encoded, pool, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_EXCHANGE_DECLARE_OK_METHOD: {
+ amqp_exchange_declare_ok_t *m =
+ (amqp_exchange_declare_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_exchange_declare_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_EXCHANGE_DELETE_METHOD: {
+ amqp_exchange_delete_t *m = (amqp_exchange_delete_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_exchange_delete_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->exchange, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->if_unused = (bit_buffer & (1 << 0)) ? 1 : 0;
+ m->nowait = (bit_buffer & (1 << 1)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_EXCHANGE_DELETE_OK_METHOD: {
+ amqp_exchange_delete_ok_t *m =
+ (amqp_exchange_delete_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_exchange_delete_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_EXCHANGE_BIND_METHOD: {
+ amqp_exchange_bind_t *m = (amqp_exchange_bind_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_exchange_bind_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->destination, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->source, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->routing_key, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->nowait = (bit_buffer & (1 << 0)) ? 1 : 0;
+ {
+ int res = amqp_decode_table(encoded, pool, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_EXCHANGE_BIND_OK_METHOD: {
+ amqp_exchange_bind_ok_t *m = (amqp_exchange_bind_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_exchange_bind_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_EXCHANGE_UNBIND_METHOD: {
+ amqp_exchange_unbind_t *m = (amqp_exchange_unbind_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_exchange_unbind_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->destination, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->source, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->routing_key, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->nowait = (bit_buffer & (1 << 0)) ? 1 : 0;
+ {
+ int res = amqp_decode_table(encoded, pool, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_EXCHANGE_UNBIND_OK_METHOD: {
+ amqp_exchange_unbind_ok_t *m =
+ (amqp_exchange_unbind_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_exchange_unbind_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_DECLARE_METHOD: {
+ amqp_queue_declare_t *m = (amqp_queue_declare_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_declare_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->queue, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->passive = (bit_buffer & (1 << 0)) ? 1 : 0;
+ m->durable = (bit_buffer & (1 << 1)) ? 1 : 0;
+ m->exclusive = (bit_buffer & (1 << 2)) ? 1 : 0;
+ m->auto_delete = (bit_buffer & (1 << 3)) ? 1 : 0;
+ m->nowait = (bit_buffer & (1 << 4)) ? 1 : 0;
+ {
+ int res = amqp_decode_table(encoded, pool, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_DECLARE_OK_METHOD: {
+ amqp_queue_declare_ok_t *m = (amqp_queue_declare_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_declare_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->queue, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_32(encoded, &offset, &m->message_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_32(encoded, &offset, &m->consumer_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_BIND_METHOD: {
+ amqp_queue_bind_t *m =
+ (amqp_queue_bind_t *)amqp_pool_alloc(pool, sizeof(amqp_queue_bind_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->queue, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->exchange, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->routing_key, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->nowait = (bit_buffer & (1 << 0)) ? 1 : 0;
+ {
+ int res = amqp_decode_table(encoded, pool, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_BIND_OK_METHOD: {
+ amqp_queue_bind_ok_t *m = (amqp_queue_bind_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_bind_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_PURGE_METHOD: {
+ amqp_queue_purge_t *m = (amqp_queue_purge_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_purge_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->queue, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->nowait = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_PURGE_OK_METHOD: {
+ amqp_queue_purge_ok_t *m = (amqp_queue_purge_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_purge_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_32(encoded, &offset, &m->message_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_DELETE_METHOD: {
+ amqp_queue_delete_t *m = (amqp_queue_delete_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_delete_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->queue, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->if_unused = (bit_buffer & (1 << 0)) ? 1 : 0;
+ m->if_empty = (bit_buffer & (1 << 1)) ? 1 : 0;
+ m->nowait = (bit_buffer & (1 << 2)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_DELETE_OK_METHOD: {
+ amqp_queue_delete_ok_t *m = (amqp_queue_delete_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_delete_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_32(encoded, &offset, &m->message_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_UNBIND_METHOD: {
+ amqp_queue_unbind_t *m = (amqp_queue_unbind_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_unbind_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->queue, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->exchange, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->routing_key, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ int res = amqp_decode_table(encoded, pool, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_QUEUE_UNBIND_OK_METHOD: {
+ amqp_queue_unbind_ok_t *m = (amqp_queue_unbind_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_unbind_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_QOS_METHOD: {
+ amqp_basic_qos_t *m =
+ (amqp_basic_qos_t *)amqp_pool_alloc(pool, sizeof(amqp_basic_qos_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_32(encoded, &offset, &m->prefetch_size))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_16(encoded, &offset, &m->prefetch_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->global = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_QOS_OK_METHOD: {
+ amqp_basic_qos_ok_t *m = (amqp_basic_qos_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_qos_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_CONSUME_METHOD: {
+ amqp_basic_consume_t *m = (amqp_basic_consume_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_consume_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->queue, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->consumer_tag, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->no_local = (bit_buffer & (1 << 0)) ? 1 : 0;
+ m->no_ack = (bit_buffer & (1 << 1)) ? 1 : 0;
+ m->exclusive = (bit_buffer & (1 << 2)) ? 1 : 0;
+ m->nowait = (bit_buffer & (1 << 3)) ? 1 : 0;
+ {
+ int res = amqp_decode_table(encoded, pool, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_CONSUME_OK_METHOD: {
+ amqp_basic_consume_ok_t *m = (amqp_basic_consume_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_consume_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->consumer_tag, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_CANCEL_METHOD: {
+ amqp_basic_cancel_t *m = (amqp_basic_cancel_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_cancel_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->consumer_tag, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->nowait = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_CANCEL_OK_METHOD: {
+ amqp_basic_cancel_ok_t *m = (amqp_basic_cancel_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_cancel_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->consumer_tag, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_PUBLISH_METHOD: {
+ amqp_basic_publish_t *m = (amqp_basic_publish_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_publish_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->exchange, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->routing_key, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->mandatory = (bit_buffer & (1 << 0)) ? 1 : 0;
+ m->immediate = (bit_buffer & (1 << 1)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_RETURN_METHOD: {
+ amqp_basic_return_t *m = (amqp_basic_return_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_return_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->reply_code))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->reply_text, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->exchange, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->routing_key, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_DELIVER_METHOD: {
+ amqp_basic_deliver_t *m = (amqp_basic_deliver_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_deliver_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->consumer_tag, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_64(encoded, &offset, &m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->redelivered = (bit_buffer & (1 << 0)) ? 1 : 0;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->exchange, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->routing_key, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_GET_METHOD: {
+ amqp_basic_get_t *m =
+ (amqp_basic_get_t *)amqp_pool_alloc(pool, sizeof(amqp_basic_get_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_16(encoded, &offset, &m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->queue, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->no_ack = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_GET_OK_METHOD: {
+ amqp_basic_get_ok_t *m = (amqp_basic_get_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_get_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_64(encoded, &offset, &m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->redelivered = (bit_buffer & (1 << 0)) ? 1 : 0;
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->exchange, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->routing_key, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (!amqp_decode_32(encoded, &offset, &m->message_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_GET_EMPTY_METHOD: {
+ amqp_basic_get_empty_t *m = (amqp_basic_get_empty_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_get_empty_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &m->cluster_id, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_ACK_METHOD: {
+ amqp_basic_ack_t *m =
+ (amqp_basic_ack_t *)amqp_pool_alloc(pool, sizeof(amqp_basic_ack_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_64(encoded, &offset, &m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->multiple = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_REJECT_METHOD: {
+ amqp_basic_reject_t *m = (amqp_basic_reject_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_reject_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_64(encoded, &offset, &m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->requeue = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_RECOVER_ASYNC_METHOD: {
+ amqp_basic_recover_async_t *m =
+ (amqp_basic_recover_async_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_recover_async_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->requeue = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_RECOVER_METHOD: {
+ amqp_basic_recover_t *m = (amqp_basic_recover_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_recover_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->requeue = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_RECOVER_OK_METHOD: {
+ amqp_basic_recover_ok_t *m = (amqp_basic_recover_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_recover_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_BASIC_NACK_METHOD: {
+ amqp_basic_nack_t *m =
+ (amqp_basic_nack_t *)amqp_pool_alloc(pool, sizeof(amqp_basic_nack_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_64(encoded, &offset, &m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->multiple = (bit_buffer & (1 << 0)) ? 1 : 0;
+ m->requeue = (bit_buffer & (1 << 1)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_TX_SELECT_METHOD: {
+ amqp_tx_select_t *m =
+ (amqp_tx_select_t *)amqp_pool_alloc(pool, sizeof(amqp_tx_select_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_TX_SELECT_OK_METHOD: {
+ amqp_tx_select_ok_t *m = (amqp_tx_select_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_tx_select_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_TX_COMMIT_METHOD: {
+ amqp_tx_commit_t *m =
+ (amqp_tx_commit_t *)amqp_pool_alloc(pool, sizeof(amqp_tx_commit_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_TX_COMMIT_OK_METHOD: {
+ amqp_tx_commit_ok_t *m = (amqp_tx_commit_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_tx_commit_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_TX_ROLLBACK_METHOD: {
+ amqp_tx_rollback_t *m = (amqp_tx_rollback_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_tx_rollback_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_TX_ROLLBACK_OK_METHOD: {
+ amqp_tx_rollback_ok_t *m = (amqp_tx_rollback_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_tx_rollback_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONFIRM_SELECT_METHOD: {
+ amqp_confirm_select_t *m = (amqp_confirm_select_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_confirm_select_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ if (!amqp_decode_8(encoded, &offset, &bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ m->nowait = (bit_buffer & (1 << 0)) ? 1 : 0;
+ *decoded = m;
+ return 0;
+ }
+ case AMQP_CONFIRM_SELECT_OK_METHOD: {
+ amqp_confirm_select_ok_t *m = (amqp_confirm_select_ok_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_confirm_select_ok_t));
+ if (m == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ *decoded = m;
+ return 0;
+ }
+ default:
+ return AMQP_STATUS_UNKNOWN_METHOD;
+ }
+}
+
+int amqp_decode_properties(uint16_t class_id, amqp_pool_t *pool,
+ amqp_bytes_t encoded, void **decoded) {
+ size_t offset = 0;
+
+ amqp_flags_t flags = 0;
+ int flagword_index = 0;
+ uint16_t partial_flags;
+
+ do {
+ if (!amqp_decode_16(encoded, &offset, &partial_flags))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ flags |= (partial_flags << (flagword_index * 16));
+ flagword_index++;
+ } while (partial_flags & 1);
+
+ switch (class_id) {
+ case 10: {
+ amqp_connection_properties_t *p =
+ (amqp_connection_properties_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_connection_properties_t));
+ if (p == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ p->_flags = flags;
+ *decoded = p;
+ return 0;
+ }
+ case 20: {
+ amqp_channel_properties_t *p =
+ (amqp_channel_properties_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_channel_properties_t));
+ if (p == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ p->_flags = flags;
+ *decoded = p;
+ return 0;
+ }
+ case 30: {
+ amqp_access_properties_t *p = (amqp_access_properties_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_access_properties_t));
+ if (p == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ p->_flags = flags;
+ *decoded = p;
+ return 0;
+ }
+ case 40: {
+ amqp_exchange_properties_t *p =
+ (amqp_exchange_properties_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_exchange_properties_t));
+ if (p == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ p->_flags = flags;
+ *decoded = p;
+ return 0;
+ }
+ case 50: {
+ amqp_queue_properties_t *p = (amqp_queue_properties_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_queue_properties_t));
+ if (p == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ p->_flags = flags;
+ *decoded = p;
+ return 0;
+ }
+ case 60: {
+ amqp_basic_properties_t *p = (amqp_basic_properties_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_basic_properties_t));
+ if (p == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ p->_flags = flags;
+ if (flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->content_type, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ if (flags & AMQP_BASIC_CONTENT_ENCODING_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->content_encoding, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ if (flags & AMQP_BASIC_HEADERS_FLAG) {
+ {
+ int res = amqp_decode_table(encoded, pool, &(p->headers), &offset);
+ if (res < 0) return res;
+ }
+ }
+ if (flags & AMQP_BASIC_DELIVERY_MODE_FLAG) {
+ if (!amqp_decode_8(encoded, &offset, &p->delivery_mode))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_PRIORITY_FLAG) {
+ if (!amqp_decode_8(encoded, &offset, &p->priority))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_CORRELATION_ID_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->correlation_id, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ if (flags & AMQP_BASIC_REPLY_TO_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->reply_to, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ if (flags & AMQP_BASIC_EXPIRATION_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->expiration, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ if (flags & AMQP_BASIC_MESSAGE_ID_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->message_id, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ if (flags & AMQP_BASIC_TIMESTAMP_FLAG) {
+ if (!amqp_decode_64(encoded, &offset, &p->timestamp))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_TYPE_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->type, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ if (flags & AMQP_BASIC_USER_ID_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->user_id, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ if (flags & AMQP_BASIC_APP_ID_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->app_id, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ if (flags & AMQP_BASIC_CLUSTER_ID_FLAG) {
+ {
+ uint8_t len;
+ if (!amqp_decode_8(encoded, &offset, &len) ||
+ !amqp_decode_bytes(encoded, &offset, &p->cluster_id, len))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ }
+ *decoded = p;
+ return 0;
+ }
+ case 90: {
+ amqp_tx_properties_t *p = (amqp_tx_properties_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_tx_properties_t));
+ if (p == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ p->_flags = flags;
+ *decoded = p;
+ return 0;
+ }
+ case 85: {
+ amqp_confirm_properties_t *p =
+ (amqp_confirm_properties_t *)amqp_pool_alloc(
+ pool, sizeof(amqp_confirm_properties_t));
+ if (p == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ p->_flags = flags;
+ *decoded = p;
+ return 0;
+ }
+ default:
+ return AMQP_STATUS_UNKNOWN_CLASS;
+ }
+}
+
+int amqp_encode_method(amqp_method_number_t methodNumber, void *decoded,
+ amqp_bytes_t encoded) {
+ size_t offset = 0;
+ uint8_t bit_buffer;
+
+ switch (methodNumber) {
+ case AMQP_CONNECTION_START_METHOD: {
+ amqp_connection_start_t *m = (amqp_connection_start_t *)decoded;
+ if (!amqp_encode_8(encoded, &offset, m->version_major))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_8(encoded, &offset, m->version_minor))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ int res = amqp_encode_table(encoded, &(m->server_properties), &offset);
+ if (res < 0) return res;
+ }
+ if (UINT32_MAX < m->mechanisms.len ||
+ !amqp_encode_32(encoded, &offset, (uint32_t)m->mechanisms.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->mechanisms))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT32_MAX < m->locales.len ||
+ !amqp_encode_32(encoded, &offset, (uint32_t)m->locales.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->locales))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_START_OK_METHOD: {
+ amqp_connection_start_ok_t *m = (amqp_connection_start_ok_t *)decoded;
+ {
+ int res = amqp_encode_table(encoded, &(m->client_properties), &offset);
+ if (res < 0) return res;
+ }
+ if (UINT8_MAX < m->mechanism.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->mechanism.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->mechanism))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT32_MAX < m->response.len ||
+ !amqp_encode_32(encoded, &offset, (uint32_t)m->response.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->response))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->locale.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->locale.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->locale))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_SECURE_METHOD: {
+ amqp_connection_secure_t *m = (amqp_connection_secure_t *)decoded;
+ if (UINT32_MAX < m->challenge.len ||
+ !amqp_encode_32(encoded, &offset, (uint32_t)m->challenge.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->challenge))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_SECURE_OK_METHOD: {
+ amqp_connection_secure_ok_t *m = (amqp_connection_secure_ok_t *)decoded;
+ if (UINT32_MAX < m->response.len ||
+ !amqp_encode_32(encoded, &offset, (uint32_t)m->response.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->response))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_TUNE_METHOD: {
+ amqp_connection_tune_t *m = (amqp_connection_tune_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->channel_max))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_32(encoded, &offset, m->frame_max))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_16(encoded, &offset, m->heartbeat))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_TUNE_OK_METHOD: {
+ amqp_connection_tune_ok_t *m = (amqp_connection_tune_ok_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->channel_max))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_32(encoded, &offset, m->frame_max))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_16(encoded, &offset, m->heartbeat))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_OPEN_METHOD: {
+ amqp_connection_open_t *m = (amqp_connection_open_t *)decoded;
+ if (UINT8_MAX < m->virtual_host.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->virtual_host.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->virtual_host))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->capabilities.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->capabilities.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->capabilities))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->insist) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_OPEN_OK_METHOD: {
+ amqp_connection_open_ok_t *m = (amqp_connection_open_ok_t *)decoded;
+ if (UINT8_MAX < m->known_hosts.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->known_hosts.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->known_hosts))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_CLOSE_METHOD: {
+ amqp_connection_close_t *m = (amqp_connection_close_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->reply_code))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->reply_text.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->reply_text.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->reply_text))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_16(encoded, &offset, m->class_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_16(encoded, &offset, m->method_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_CLOSE_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_BLOCKED_METHOD: {
+ amqp_connection_blocked_t *m = (amqp_connection_blocked_t *)decoded;
+ if (UINT8_MAX < m->reason.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->reason.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->reason))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONNECTION_UNBLOCKED_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_CHANNEL_OPEN_METHOD: {
+ amqp_channel_open_t *m = (amqp_channel_open_t *)decoded;
+ if (UINT8_MAX < m->out_of_band.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->out_of_band.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->out_of_band))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CHANNEL_OPEN_OK_METHOD: {
+ amqp_channel_open_ok_t *m = (amqp_channel_open_ok_t *)decoded;
+ if (UINT32_MAX < m->channel_id.len ||
+ !amqp_encode_32(encoded, &offset, (uint32_t)m->channel_id.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->channel_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CHANNEL_FLOW_METHOD: {
+ amqp_channel_flow_t *m = (amqp_channel_flow_t *)decoded;
+ bit_buffer = 0;
+ if (m->active) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CHANNEL_FLOW_OK_METHOD: {
+ amqp_channel_flow_ok_t *m = (amqp_channel_flow_ok_t *)decoded;
+ bit_buffer = 0;
+ if (m->active) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CHANNEL_CLOSE_METHOD: {
+ amqp_channel_close_t *m = (amqp_channel_close_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->reply_code))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->reply_text.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->reply_text.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->reply_text))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_16(encoded, &offset, m->class_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_16(encoded, &offset, m->method_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CHANNEL_CLOSE_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_ACCESS_REQUEST_METHOD: {
+ amqp_access_request_t *m = (amqp_access_request_t *)decoded;
+ if (UINT8_MAX < m->realm.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->realm.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->realm))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->exclusive) bit_buffer |= (1 << 0);
+ if (m->passive) bit_buffer |= (1 << 1);
+ if (m->active) bit_buffer |= (1 << 2);
+ if (m->write) bit_buffer |= (1 << 3);
+ if (m->read) bit_buffer |= (1 << 4);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_ACCESS_REQUEST_OK_METHOD: {
+ amqp_access_request_ok_t *m = (amqp_access_request_ok_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_EXCHANGE_DECLARE_METHOD: {
+ amqp_exchange_declare_t *m = (amqp_exchange_declare_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->exchange.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->exchange.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->exchange))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->type.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->type.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->type))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->passive) bit_buffer |= (1 << 0);
+ if (m->durable) bit_buffer |= (1 << 1);
+ if (m->auto_delete) bit_buffer |= (1 << 2);
+ if (m->internal) bit_buffer |= (1 << 3);
+ if (m->nowait) bit_buffer |= (1 << 4);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ int res = amqp_encode_table(encoded, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ return (int)offset;
+ }
+ case AMQP_EXCHANGE_DECLARE_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_EXCHANGE_DELETE_METHOD: {
+ amqp_exchange_delete_t *m = (amqp_exchange_delete_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->exchange.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->exchange.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->exchange))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->if_unused) bit_buffer |= (1 << 0);
+ if (m->nowait) bit_buffer |= (1 << 1);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_EXCHANGE_DELETE_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_EXCHANGE_BIND_METHOD: {
+ amqp_exchange_bind_t *m = (amqp_exchange_bind_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->destination.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->destination.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->destination))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->source.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->source.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->source))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->routing_key.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->routing_key.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->routing_key))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->nowait) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ int res = amqp_encode_table(encoded, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ return (int)offset;
+ }
+ case AMQP_EXCHANGE_BIND_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_EXCHANGE_UNBIND_METHOD: {
+ amqp_exchange_unbind_t *m = (amqp_exchange_unbind_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->destination.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->destination.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->destination))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->source.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->source.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->source))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->routing_key.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->routing_key.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->routing_key))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->nowait) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ int res = amqp_encode_table(encoded, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ return (int)offset;
+ }
+ case AMQP_EXCHANGE_UNBIND_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_QUEUE_DECLARE_METHOD: {
+ amqp_queue_declare_t *m = (amqp_queue_declare_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->queue.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->queue.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->queue))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->passive) bit_buffer |= (1 << 0);
+ if (m->durable) bit_buffer |= (1 << 1);
+ if (m->exclusive) bit_buffer |= (1 << 2);
+ if (m->auto_delete) bit_buffer |= (1 << 3);
+ if (m->nowait) bit_buffer |= (1 << 4);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ int res = amqp_encode_table(encoded, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ return (int)offset;
+ }
+ case AMQP_QUEUE_DECLARE_OK_METHOD: {
+ amqp_queue_declare_ok_t *m = (amqp_queue_declare_ok_t *)decoded;
+ if (UINT8_MAX < m->queue.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->queue.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->queue))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_32(encoded, &offset, m->message_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_32(encoded, &offset, m->consumer_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_QUEUE_BIND_METHOD: {
+ amqp_queue_bind_t *m = (amqp_queue_bind_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->queue.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->queue.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->queue))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->exchange.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->exchange.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->exchange))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->routing_key.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->routing_key.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->routing_key))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->nowait) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ int res = amqp_encode_table(encoded, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ return (int)offset;
+ }
+ case AMQP_QUEUE_BIND_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_QUEUE_PURGE_METHOD: {
+ amqp_queue_purge_t *m = (amqp_queue_purge_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->queue.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->queue.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->queue))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->nowait) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_QUEUE_PURGE_OK_METHOD: {
+ amqp_queue_purge_ok_t *m = (amqp_queue_purge_ok_t *)decoded;
+ if (!amqp_encode_32(encoded, &offset, m->message_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_QUEUE_DELETE_METHOD: {
+ amqp_queue_delete_t *m = (amqp_queue_delete_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->queue.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->queue.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->queue))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->if_unused) bit_buffer |= (1 << 0);
+ if (m->if_empty) bit_buffer |= (1 << 1);
+ if (m->nowait) bit_buffer |= (1 << 2);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_QUEUE_DELETE_OK_METHOD: {
+ amqp_queue_delete_ok_t *m = (amqp_queue_delete_ok_t *)decoded;
+ if (!amqp_encode_32(encoded, &offset, m->message_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_QUEUE_UNBIND_METHOD: {
+ amqp_queue_unbind_t *m = (amqp_queue_unbind_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->queue.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->queue.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->queue))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->exchange.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->exchange.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->exchange))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->routing_key.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->routing_key.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->routing_key))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ int res = amqp_encode_table(encoded, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ return (int)offset;
+ }
+ case AMQP_QUEUE_UNBIND_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_BASIC_QOS_METHOD: {
+ amqp_basic_qos_t *m = (amqp_basic_qos_t *)decoded;
+ if (!amqp_encode_32(encoded, &offset, m->prefetch_size))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_16(encoded, &offset, m->prefetch_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->global) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_QOS_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_BASIC_CONSUME_METHOD: {
+ amqp_basic_consume_t *m = (amqp_basic_consume_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->queue.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->queue.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->queue))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->consumer_tag.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->consumer_tag.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->consumer_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->no_local) bit_buffer |= (1 << 0);
+ if (m->no_ack) bit_buffer |= (1 << 1);
+ if (m->exclusive) bit_buffer |= (1 << 2);
+ if (m->nowait) bit_buffer |= (1 << 3);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ {
+ int res = amqp_encode_table(encoded, &(m->arguments), &offset);
+ if (res < 0) return res;
+ }
+ return (int)offset;
+ }
+ case AMQP_BASIC_CONSUME_OK_METHOD: {
+ amqp_basic_consume_ok_t *m = (amqp_basic_consume_ok_t *)decoded;
+ if (UINT8_MAX < m->consumer_tag.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->consumer_tag.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->consumer_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_CANCEL_METHOD: {
+ amqp_basic_cancel_t *m = (amqp_basic_cancel_t *)decoded;
+ if (UINT8_MAX < m->consumer_tag.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->consumer_tag.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->consumer_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->nowait) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_CANCEL_OK_METHOD: {
+ amqp_basic_cancel_ok_t *m = (amqp_basic_cancel_ok_t *)decoded;
+ if (UINT8_MAX < m->consumer_tag.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->consumer_tag.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->consumer_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_PUBLISH_METHOD: {
+ amqp_basic_publish_t *m = (amqp_basic_publish_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->exchange.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->exchange.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->exchange))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->routing_key.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->routing_key.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->routing_key))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->mandatory) bit_buffer |= (1 << 0);
+ if (m->immediate) bit_buffer |= (1 << 1);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_RETURN_METHOD: {
+ amqp_basic_return_t *m = (amqp_basic_return_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->reply_code))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->reply_text.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->reply_text.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->reply_text))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->exchange.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->exchange.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->exchange))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->routing_key.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->routing_key.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->routing_key))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_DELIVER_METHOD: {
+ amqp_basic_deliver_t *m = (amqp_basic_deliver_t *)decoded;
+ if (UINT8_MAX < m->consumer_tag.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->consumer_tag.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->consumer_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_64(encoded, &offset, m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->redelivered) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->exchange.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->exchange.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->exchange))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->routing_key.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->routing_key.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->routing_key))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_GET_METHOD: {
+ amqp_basic_get_t *m = (amqp_basic_get_t *)decoded;
+ if (!amqp_encode_16(encoded, &offset, m->ticket))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->queue.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->queue.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->queue))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->no_ack) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_GET_OK_METHOD: {
+ amqp_basic_get_ok_t *m = (amqp_basic_get_ok_t *)decoded;
+ if (!amqp_encode_64(encoded, &offset, m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->redelivered) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->exchange.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->exchange.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->exchange))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (UINT8_MAX < m->routing_key.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->routing_key.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->routing_key))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_encode_32(encoded, &offset, m->message_count))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_GET_EMPTY_METHOD: {
+ amqp_basic_get_empty_t *m = (amqp_basic_get_empty_t *)decoded;
+ if (UINT8_MAX < m->cluster_id.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)m->cluster_id.len) ||
+ !amqp_encode_bytes(encoded, &offset, m->cluster_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_ACK_METHOD: {
+ amqp_basic_ack_t *m = (amqp_basic_ack_t *)decoded;
+ if (!amqp_encode_64(encoded, &offset, m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->multiple) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_REJECT_METHOD: {
+ amqp_basic_reject_t *m = (amqp_basic_reject_t *)decoded;
+ if (!amqp_encode_64(encoded, &offset, m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->requeue) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_RECOVER_ASYNC_METHOD: {
+ amqp_basic_recover_async_t *m = (amqp_basic_recover_async_t *)decoded;
+ bit_buffer = 0;
+ if (m->requeue) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_RECOVER_METHOD: {
+ amqp_basic_recover_t *m = (amqp_basic_recover_t *)decoded;
+ bit_buffer = 0;
+ if (m->requeue) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_BASIC_RECOVER_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_BASIC_NACK_METHOD: {
+ amqp_basic_nack_t *m = (amqp_basic_nack_t *)decoded;
+ if (!amqp_encode_64(encoded, &offset, m->delivery_tag))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ bit_buffer = 0;
+ if (m->multiple) bit_buffer |= (1 << 0);
+ if (m->requeue) bit_buffer |= (1 << 1);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_TX_SELECT_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_TX_SELECT_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_TX_COMMIT_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_TX_COMMIT_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_TX_ROLLBACK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_TX_ROLLBACK_OK_METHOD: {
+ return (int)offset;
+ }
+ case AMQP_CONFIRM_SELECT_METHOD: {
+ amqp_confirm_select_t *m = (amqp_confirm_select_t *)decoded;
+ bit_buffer = 0;
+ if (m->nowait) bit_buffer |= (1 << 0);
+ if (!amqp_encode_8(encoded, &offset, bit_buffer))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ return (int)offset;
+ }
+ case AMQP_CONFIRM_SELECT_OK_METHOD: {
+ return (int)offset;
+ }
+ default:
+ return AMQP_STATUS_UNKNOWN_METHOD;
+ }
+}
+
+int amqp_encode_properties(uint16_t class_id, void *decoded,
+ amqp_bytes_t encoded) {
+ size_t offset = 0;
+
+ /* Cheat, and get the flags out generically, relying on the
+ similarity of structure between classes */
+ amqp_flags_t flags = *(amqp_flags_t *)decoded; /* cheating! */
+
+ {
+ /* We take a copy of flags to avoid destroying it, as it is used
+ in the autogenerated code below. */
+ amqp_flags_t remaining_flags = flags;
+ do {
+ amqp_flags_t remainder = remaining_flags >> 16;
+ uint16_t partial_flags = remaining_flags & 0xFFFE;
+ if (remainder != 0) {
+ partial_flags |= 1;
+ }
+ if (!amqp_encode_16(encoded, &offset, partial_flags))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ remaining_flags = remainder;
+ } while (remaining_flags != 0);
+ }
+
+ switch (class_id) {
+ case 10: {
+ return (int)offset;
+ }
+ case 20: {
+ return (int)offset;
+ }
+ case 30: {
+ return (int)offset;
+ }
+ case 40: {
+ return (int)offset;
+ }
+ case 50: {
+ return (int)offset;
+ }
+ case 60: {
+ amqp_basic_properties_t *p = (amqp_basic_properties_t *)decoded;
+ if (flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
+ if (UINT8_MAX < p->content_type.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)p->content_type.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->content_type))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_CONTENT_ENCODING_FLAG) {
+ if (UINT8_MAX < p->content_encoding.len ||
+ !amqp_encode_8(encoded, &offset,
+ (uint8_t)p->content_encoding.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->content_encoding))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_HEADERS_FLAG) {
+ {
+ int res = amqp_encode_table(encoded, &(p->headers), &offset);
+ if (res < 0) return res;
+ }
+ }
+ if (flags & AMQP_BASIC_DELIVERY_MODE_FLAG) {
+ if (!amqp_encode_8(encoded, &offset, p->delivery_mode))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_PRIORITY_FLAG) {
+ if (!amqp_encode_8(encoded, &offset, p->priority))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_CORRELATION_ID_FLAG) {
+ if (UINT8_MAX < p->correlation_id.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)p->correlation_id.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->correlation_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_REPLY_TO_FLAG) {
+ if (UINT8_MAX < p->reply_to.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)p->reply_to.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->reply_to))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_EXPIRATION_FLAG) {
+ if (UINT8_MAX < p->expiration.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)p->expiration.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->expiration))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_MESSAGE_ID_FLAG) {
+ if (UINT8_MAX < p->message_id.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)p->message_id.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->message_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_TIMESTAMP_FLAG) {
+ if (!amqp_encode_64(encoded, &offset, p->timestamp))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_TYPE_FLAG) {
+ if (UINT8_MAX < p->type.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)p->type.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->type))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_USER_ID_FLAG) {
+ if (UINT8_MAX < p->user_id.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)p->user_id.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->user_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_APP_ID_FLAG) {
+ if (UINT8_MAX < p->app_id.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)p->app_id.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->app_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ if (flags & AMQP_BASIC_CLUSTER_ID_FLAG) {
+ if (UINT8_MAX < p->cluster_id.len ||
+ !amqp_encode_8(encoded, &offset, (uint8_t)p->cluster_id.len) ||
+ !amqp_encode_bytes(encoded, &offset, p->cluster_id))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+ return (int)offset;
+ }
+ case 90: {
+ return (int)offset;
+ }
+ case 85: {
+ return (int)offset;
+ }
+ default:
+ return AMQP_STATUS_UNKNOWN_CLASS;
+ }
+}
+
+/**
+ * amqp_channel_open
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @returns amqp_channel_open_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_channel_open_ok_t *AMQP_CALL
+ amqp_channel_open(amqp_connection_state_t state, amqp_channel_t channel) {
+ amqp_channel_open_t req;
+ req.out_of_band = amqp_empty_bytes;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_CHANNEL_OPEN_METHOD,
+ AMQP_CHANNEL_OPEN_OK_METHOD, &req);
+}
+
+/**
+ * amqp_channel_flow
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] active active
+ * @returns amqp_channel_flow_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_channel_flow_ok_t *AMQP_CALL
+ amqp_channel_flow(amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_boolean_t active) {
+ amqp_channel_flow_t req;
+ req.active = active;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_CHANNEL_FLOW_METHOD,
+ AMQP_CHANNEL_FLOW_OK_METHOD, &req);
+}
+
+/**
+ * amqp_exchange_declare
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] exchange exchange
+ * @param [in] type type
+ * @param [in] passive passive
+ * @param [in] durable durable
+ * @param [in] auto_delete auto_delete
+ * @param [in] internal internal
+ * @param [in] arguments arguments
+ * @returns amqp_exchange_declare_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_exchange_declare_ok_t *AMQP_CALL amqp_exchange_declare(
+ amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_bytes_t exchange, amqp_bytes_t type, amqp_boolean_t passive,
+ amqp_boolean_t durable, amqp_boolean_t auto_delete, amqp_boolean_t internal,
+ amqp_table_t arguments) {
+ amqp_exchange_declare_t req;
+ req.ticket = 0;
+ req.exchange = exchange;
+ req.type = type;
+ req.passive = passive;
+ req.durable = durable;
+ req.auto_delete = auto_delete;
+ req.internal = internal;
+ req.nowait = 0;
+ req.arguments = arguments;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_EXCHANGE_DECLARE_METHOD,
+ AMQP_EXCHANGE_DECLARE_OK_METHOD, &req);
+}
+
+/**
+ * amqp_exchange_delete
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] exchange exchange
+ * @param [in] if_unused if_unused
+ * @returns amqp_exchange_delete_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_exchange_delete_ok_t *AMQP_CALL
+ amqp_exchange_delete(amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_bytes_t exchange, amqp_boolean_t if_unused) {
+ amqp_exchange_delete_t req;
+ req.ticket = 0;
+ req.exchange = exchange;
+ req.if_unused = if_unused;
+ req.nowait = 0;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_EXCHANGE_DELETE_METHOD,
+ AMQP_EXCHANGE_DELETE_OK_METHOD, &req);
+}
+
+/**
+ * amqp_exchange_bind
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] destination destination
+ * @param [in] source source
+ * @param [in] routing_key routing_key
+ * @param [in] arguments arguments
+ * @returns amqp_exchange_bind_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_exchange_bind_ok_t *AMQP_CALL
+ amqp_exchange_bind(amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_bytes_t destination, amqp_bytes_t source,
+ amqp_bytes_t routing_key, amqp_table_t arguments) {
+ amqp_exchange_bind_t req;
+ req.ticket = 0;
+ req.destination = destination;
+ req.source = source;
+ req.routing_key = routing_key;
+ req.nowait = 0;
+ req.arguments = arguments;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_EXCHANGE_BIND_METHOD,
+ AMQP_EXCHANGE_BIND_OK_METHOD, &req);
+}
+
+/**
+ * amqp_exchange_unbind
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] destination destination
+ * @param [in] source source
+ * @param [in] routing_key routing_key
+ * @param [in] arguments arguments
+ * @returns amqp_exchange_unbind_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_exchange_unbind_ok_t *AMQP_CALL
+ amqp_exchange_unbind(amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_bytes_t destination, amqp_bytes_t source,
+ amqp_bytes_t routing_key, amqp_table_t arguments) {
+ amqp_exchange_unbind_t req;
+ req.ticket = 0;
+ req.destination = destination;
+ req.source = source;
+ req.routing_key = routing_key;
+ req.nowait = 0;
+ req.arguments = arguments;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_EXCHANGE_UNBIND_METHOD,
+ AMQP_EXCHANGE_UNBIND_OK_METHOD, &req);
+}
+
+/**
+ * amqp_queue_declare
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] queue queue
+ * @param [in] passive passive
+ * @param [in] durable durable
+ * @param [in] exclusive exclusive
+ * @param [in] auto_delete auto_delete
+ * @param [in] arguments arguments
+ * @returns amqp_queue_declare_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_queue_declare_ok_t *AMQP_CALL amqp_queue_declare(
+ amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,
+ amqp_boolean_t passive, amqp_boolean_t durable, amqp_boolean_t exclusive,
+ amqp_boolean_t auto_delete, amqp_table_t arguments) {
+ amqp_queue_declare_t req;
+ req.ticket = 0;
+ req.queue = queue;
+ req.passive = passive;
+ req.durable = durable;
+ req.exclusive = exclusive;
+ req.auto_delete = auto_delete;
+ req.nowait = 0;
+ req.arguments = arguments;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_QUEUE_DECLARE_METHOD,
+ AMQP_QUEUE_DECLARE_OK_METHOD, &req);
+}
+
+/**
+ * amqp_queue_bind
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] queue queue
+ * @param [in] exchange exchange
+ * @param [in] routing_key routing_key
+ * @param [in] arguments arguments
+ * @returns amqp_queue_bind_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_queue_bind_ok_t *AMQP_CALL amqp_queue_bind(
+ amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,
+ amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_table_t arguments) {
+ amqp_queue_bind_t req;
+ req.ticket = 0;
+ req.queue = queue;
+ req.exchange = exchange;
+ req.routing_key = routing_key;
+ req.nowait = 0;
+ req.arguments = arguments;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_QUEUE_BIND_METHOD,
+ AMQP_QUEUE_BIND_OK_METHOD, &req);
+}
+
+/**
+ * amqp_queue_purge
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] queue queue
+ * @returns amqp_queue_purge_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_queue_purge_ok_t *AMQP_CALL amqp_queue_purge(amqp_connection_state_t state,
+ amqp_channel_t channel,
+ amqp_bytes_t queue) {
+ amqp_queue_purge_t req;
+ req.ticket = 0;
+ req.queue = queue;
+ req.nowait = 0;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_QUEUE_PURGE_METHOD,
+ AMQP_QUEUE_PURGE_OK_METHOD, &req);
+}
+
+/**
+ * amqp_queue_delete
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] queue queue
+ * @param [in] if_unused if_unused
+ * @param [in] if_empty if_empty
+ * @returns amqp_queue_delete_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_queue_delete_ok_t *AMQP_CALL amqp_queue_delete(
+ amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,
+ amqp_boolean_t if_unused, amqp_boolean_t if_empty) {
+ amqp_queue_delete_t req;
+ req.ticket = 0;
+ req.queue = queue;
+ req.if_unused = if_unused;
+ req.if_empty = if_empty;
+ req.nowait = 0;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_QUEUE_DELETE_METHOD,
+ AMQP_QUEUE_DELETE_OK_METHOD, &req);
+}
+
+/**
+ * amqp_queue_unbind
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] queue queue
+ * @param [in] exchange exchange
+ * @param [in] routing_key routing_key
+ * @param [in] arguments arguments
+ * @returns amqp_queue_unbind_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_queue_unbind_ok_t *AMQP_CALL amqp_queue_unbind(
+ amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,
+ amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_table_t arguments) {
+ amqp_queue_unbind_t req;
+ req.ticket = 0;
+ req.queue = queue;
+ req.exchange = exchange;
+ req.routing_key = routing_key;
+ req.arguments = arguments;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_QUEUE_UNBIND_METHOD,
+ AMQP_QUEUE_UNBIND_OK_METHOD, &req);
+}
+
+/**
+ * amqp_basic_qos
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] prefetch_size prefetch_size
+ * @param [in] prefetch_count prefetch_count
+ * @param [in] global global
+ * @returns amqp_basic_qos_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_basic_qos_ok_t *AMQP_CALL amqp_basic_qos(amqp_connection_state_t state,
+ amqp_channel_t channel,
+ uint32_t prefetch_size,
+ uint16_t prefetch_count,
+ amqp_boolean_t global) {
+ amqp_basic_qos_t req;
+ req.prefetch_size = prefetch_size;
+ req.prefetch_count = prefetch_count;
+ req.global = global;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_BASIC_QOS_METHOD,
+ AMQP_BASIC_QOS_OK_METHOD, &req);
+}
+
+/**
+ * amqp_basic_consume
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] queue queue
+ * @param [in] consumer_tag consumer_tag
+ * @param [in] no_local no_local
+ * @param [in] no_ack no_ack
+ * @param [in] exclusive exclusive
+ * @param [in] arguments arguments
+ * @returns amqp_basic_consume_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_basic_consume_ok_t *AMQP_CALL amqp_basic_consume(
+ amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,
+ amqp_bytes_t consumer_tag, amqp_boolean_t no_local, amqp_boolean_t no_ack,
+ amqp_boolean_t exclusive, amqp_table_t arguments) {
+ amqp_basic_consume_t req;
+ req.ticket = 0;
+ req.queue = queue;
+ req.consumer_tag = consumer_tag;
+ req.no_local = no_local;
+ req.no_ack = no_ack;
+ req.exclusive = exclusive;
+ req.nowait = 0;
+ req.arguments = arguments;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_BASIC_CONSUME_METHOD,
+ AMQP_BASIC_CONSUME_OK_METHOD, &req);
+}
+
+/**
+ * amqp_basic_cancel
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] consumer_tag consumer_tag
+ * @returns amqp_basic_cancel_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_basic_cancel_ok_t *AMQP_CALL
+ amqp_basic_cancel(amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_bytes_t consumer_tag) {
+ amqp_basic_cancel_t req;
+ req.consumer_tag = consumer_tag;
+ req.nowait = 0;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_BASIC_CANCEL_METHOD,
+ AMQP_BASIC_CANCEL_OK_METHOD, &req);
+}
+
+/**
+ * amqp_basic_recover
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @param [in] requeue requeue
+ * @returns amqp_basic_recover_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_basic_recover_ok_t *AMQP_CALL
+ amqp_basic_recover(amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_boolean_t requeue) {
+ amqp_basic_recover_t req;
+ req.requeue = requeue;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_BASIC_RECOVER_METHOD,
+ AMQP_BASIC_RECOVER_OK_METHOD, &req);
+}
+
+/**
+ * amqp_tx_select
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @returns amqp_tx_select_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_tx_select_ok_t *AMQP_CALL amqp_tx_select(amqp_connection_state_t state,
+ amqp_channel_t channel) {
+ amqp_tx_select_t req;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_TX_SELECT_METHOD,
+ AMQP_TX_SELECT_OK_METHOD, &req);
+}
+
+/**
+ * amqp_tx_commit
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @returns amqp_tx_commit_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_tx_commit_ok_t *AMQP_CALL amqp_tx_commit(amqp_connection_state_t state,
+ amqp_channel_t channel) {
+ amqp_tx_commit_t req;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_TX_COMMIT_METHOD,
+ AMQP_TX_COMMIT_OK_METHOD, &req);
+}
+
+/**
+ * amqp_tx_rollback
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @returns amqp_tx_rollback_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_tx_rollback_ok_t *AMQP_CALL amqp_tx_rollback(amqp_connection_state_t state,
+ amqp_channel_t channel) {
+ amqp_tx_rollback_t req;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_TX_ROLLBACK_METHOD,
+ AMQP_TX_ROLLBACK_OK_METHOD, &req);
+}
+
+/**
+ * amqp_confirm_select
+ *
+ * @param [in] state connection state
+ * @param [in] channel the channel to do the RPC on
+ * @returns amqp_confirm_select_ok_t
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_confirm_select_ok_t *AMQP_CALL
+ amqp_confirm_select(amqp_connection_state_t state, amqp_channel_t channel) {
+ amqp_confirm_select_t req;
+ req.nowait = 0;
+
+ return amqp_simple_rpc_decoded(state, channel, AMQP_CONFIRM_SELECT_METHOD,
+ AMQP_CONFIRM_SELECT_OK_METHOD, &req);
+}
diff --git a/ext/librabbitmq/centos_x64/include/amqp_framing.h b/ext/librabbitmq/librabbitmq/amqp_framing.h
similarity index 100%
rename from ext/librabbitmq/centos_x64/include/amqp_framing.h
rename to ext/librabbitmq/librabbitmq/amqp_framing.h
diff --git a/ext/librabbitmq/librabbitmq/amqp_hostcheck.c b/ext/librabbitmq/librabbitmq/amqp_hostcheck.c
new file mode 100644
index 000000000..5a4f73399
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_hostcheck.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright 1996-2014 Daniel Stenberg .
+ * Copyright 2014 Michael Steinert
+ *
+ * All rights reserved.
+ *
+ * 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", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization of the
+ * copyright holder.
+ */
+
+#include "amqp_hostcheck.h"
+
+#include
+
+/* Portable, consistent toupper (remember EBCDIC). Do not use toupper()
+ * because its behavior is altered by the current locale.
+ */
+
+static char amqp_raw_toupper(char in) {
+ switch (in) {
+ case 'a':
+ return 'A';
+ case 'b':
+ return 'B';
+ case 'c':
+ return 'C';
+ case 'd':
+ return 'D';
+ case 'e':
+ return 'E';
+ case 'f':
+ return 'F';
+ case 'g':
+ return 'G';
+ case 'h':
+ return 'H';
+ case 'i':
+ return 'I';
+ case 'j':
+ return 'J';
+ case 'k':
+ return 'K';
+ case 'l':
+ return 'L';
+ case 'm':
+ return 'M';
+ case 'n':
+ return 'N';
+ case 'o':
+ return 'O';
+ case 'p':
+ return 'P';
+ case 'q':
+ return 'Q';
+ case 'r':
+ return 'R';
+ case 's':
+ return 'S';
+ case 't':
+ return 'T';
+ case 'u':
+ return 'U';
+ case 'v':
+ return 'V';
+ case 'w':
+ return 'W';
+ case 'x':
+ return 'X';
+ case 'y':
+ return 'Y';
+ case 'z':
+ return 'Z';
+ }
+ return in;
+}
+
+/*
+ * amqp_raw_equal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
+ * some further explanation to why this function is necessary.
+ *
+ * The function is capable of comparing a-z case insensitively even for
+ * non-ascii.
+ */
+
+static int amqp_raw_equal(const char *first, const char *second) {
+ while (*first && *second) {
+ if (amqp_raw_toupper(*first) != amqp_raw_toupper(*second)) {
+ /* get out of the loop as soon as they don't match */
+ break;
+ }
+ first++;
+ second++;
+ }
+ /* we do the comparison here (possibly again), just to make sure that if
+ * the loop above is skipped because one of the strings reached zero, we
+ * must not return this as a successful match
+ */
+ return (amqp_raw_toupper(*first) == amqp_raw_toupper(*second));
+}
+
+static int amqp_raw_nequal(const char *first, const char *second, size_t max) {
+ while (*first && *second && max) {
+ if (amqp_raw_toupper(*first) != amqp_raw_toupper(*second)) {
+ break;
+ }
+ max--;
+ first++;
+ second++;
+ }
+ if (0 == max) {
+ return 1; /* they are equal this far */
+ }
+ return amqp_raw_toupper(*first) == amqp_raw_toupper(*second);
+}
+
+/*
+ * Match a hostname against a wildcard pattern.
+ * E.g.
+ * "foo.host.com" matches "*.host.com".
+ *
+ * We use the matching rule described in RFC6125, section 6.4.3.
+ * http://tools.ietf.org/html/rfc6125#section-6.4.3
+ */
+
+static amqp_hostcheck_result amqp_hostmatch(const char *hostname,
+ const char *pattern) {
+ const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
+ int wildcard_enabled;
+ size_t prefixlen, suffixlen;
+ pattern_wildcard = strchr(pattern, '*');
+ if (pattern_wildcard == NULL) {
+ return amqp_raw_equal(pattern, hostname) ? AMQP_HCR_MATCH
+ : AMQP_HCR_NO_MATCH;
+ }
+ /* We require at least 2 dots in pattern to avoid too wide wildcard match. */
+ wildcard_enabled = 1;
+ pattern_label_end = strchr(pattern, '.');
+ if (pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL ||
+ pattern_wildcard > pattern_label_end ||
+ amqp_raw_nequal(pattern, "xn--", 4)) {
+ wildcard_enabled = 0;
+ }
+ if (!wildcard_enabled) {
+ return amqp_raw_equal(pattern, hostname) ? AMQP_HCR_MATCH
+ : AMQP_HCR_NO_MATCH;
+ }
+ hostname_label_end = strchr(hostname, '.');
+ if (hostname_label_end == NULL ||
+ !amqp_raw_equal(pattern_label_end, hostname_label_end)) {
+ return AMQP_HCR_NO_MATCH;
+ }
+ /* The wildcard must match at least one character, so the left-most
+ * label of the hostname is at least as large as the left-most label
+ * of the pattern.
+ */
+ if (hostname_label_end - hostname < pattern_label_end - pattern) {
+ return AMQP_HCR_NO_MATCH;
+ }
+ prefixlen = pattern_wildcard - pattern;
+ suffixlen = pattern_label_end - (pattern_wildcard + 1);
+ return amqp_raw_nequal(pattern, hostname, prefixlen) &&
+ amqp_raw_nequal(pattern_wildcard + 1,
+ hostname_label_end - suffixlen, suffixlen)
+ ? AMQP_HCR_MATCH
+ : AMQP_HCR_NO_MATCH;
+}
+
+amqp_hostcheck_result amqp_hostcheck(const char *match_pattern,
+ const char *hostname) {
+ /* sanity check */
+ if (!match_pattern || !*match_pattern || !hostname || !*hostname) {
+ return AMQP_HCR_NO_MATCH;
+ }
+ /* trivial case */
+ if (amqp_raw_equal(hostname, match_pattern)) {
+ return AMQP_HCR_MATCH;
+ }
+ return amqp_hostmatch(hostname, match_pattern);
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_hostcheck.h b/ext/librabbitmq/librabbitmq/amqp_hostcheck.h
new file mode 100644
index 000000000..7ab5c267b
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_hostcheck.h
@@ -0,0 +1,48 @@
+#ifndef librabbitmq_amqp_hostcheck_h
+#define librabbitmq_amqp_hostcheck_h
+
+/*
+ * Copyright 1996-2014 Daniel Stenberg .
+ * Copyright 2014 Michael Steinert
+ *
+ * All rights reserved.
+ *
+ * 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", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization of the
+ * copyright holder.
+ */
+
+typedef enum {
+ AMQP_HCR_NO_MATCH = 0,
+ AMQP_HCR_MATCH = 1
+} amqp_hostcheck_result;
+
+/**
+ * Determine whether hostname matches match_pattern.
+ *
+ * match_pattern may include wildcards.
+ *
+ * Match is performed based on the rules set forth in RFC6125 section 6.4.3.
+ * http://tools.ietf.org/html/rfc6125#section-6.4.3
+ *
+ * \param match_pattern RFC6125 compliant pattern
+ * \param hostname to match against
+ * \returns AMQP_HCR_MATCH if its a match, AMQP_HCR_NO_MATCH otherwise.
+ */
+amqp_hostcheck_result amqp_hostcheck(const char *match_pattern,
+ const char *hostname);
+
+#endif
diff --git a/ext/librabbitmq/librabbitmq/amqp_mem.c b/ext/librabbitmq/librabbitmq/amqp_mem.c
new file mode 100644
index 000000000..f0d47cc73
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_mem.c
@@ -0,0 +1,242 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "amqp_private.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+char const *amqp_version(void) { return AMQP_VERSION_STRING; }
+
+uint32_t amqp_version_number(void) { return AMQP_VERSION; }
+
+void init_amqp_pool(amqp_pool_t *pool, size_t pagesize) {
+ pool->pagesize = pagesize ? pagesize : 4096;
+
+ pool->pages.num_blocks = 0;
+ pool->pages.blocklist = NULL;
+
+ pool->large_blocks.num_blocks = 0;
+ pool->large_blocks.blocklist = NULL;
+
+ pool->next_page = 0;
+ pool->alloc_block = NULL;
+ pool->alloc_used = 0;
+}
+
+static void empty_blocklist(amqp_pool_blocklist_t *x) {
+ int i;
+
+ if (x->blocklist != NULL) {
+ for (i = 0; i < x->num_blocks; i++) {
+ free(x->blocklist[i]);
+ }
+ free(x->blocklist);
+ }
+ x->num_blocks = 0;
+ x->blocklist = NULL;
+}
+
+void recycle_amqp_pool(amqp_pool_t *pool) {
+ empty_blocklist(&pool->large_blocks);
+ pool->next_page = 0;
+ pool->alloc_block = NULL;
+ pool->alloc_used = 0;
+}
+
+void empty_amqp_pool(amqp_pool_t *pool) {
+ recycle_amqp_pool(pool);
+ empty_blocklist(&pool->pages);
+}
+
+/* Returns 1 on success, 0 on failure */
+static int record_pool_block(amqp_pool_blocklist_t *x, void *block) {
+ size_t blocklistlength = sizeof(void *) * (x->num_blocks + 1);
+
+ if (x->blocklist == NULL) {
+ x->blocklist = malloc(blocklistlength);
+ if (x->blocklist == NULL) {
+ return 0;
+ }
+ } else {
+ void *newbl = realloc(x->blocklist, blocklistlength);
+ if (newbl == NULL) {
+ return 0;
+ }
+ x->blocklist = newbl;
+ }
+
+ x->blocklist[x->num_blocks] = block;
+ x->num_blocks++;
+ return 1;
+}
+
+void *amqp_pool_alloc(amqp_pool_t *pool, size_t amount) {
+ if (amount == 0) {
+ return NULL;
+ }
+
+ amount = (amount + 7) & (~7); /* round up to nearest 8-byte boundary */
+
+ if (amount > pool->pagesize) {
+ void *result = calloc(1, amount);
+ if (result == NULL) {
+ return NULL;
+ }
+ if (!record_pool_block(&pool->large_blocks, result)) {
+ free(result);
+ return NULL;
+ }
+ return result;
+ }
+
+ if (pool->alloc_block != NULL) {
+ assert(pool->alloc_used <= pool->pagesize);
+
+ if (pool->alloc_used + amount <= pool->pagesize) {
+ void *result = pool->alloc_block + pool->alloc_used;
+ pool->alloc_used += amount;
+ return result;
+ }
+ }
+
+ if (pool->next_page >= pool->pages.num_blocks) {
+ pool->alloc_block = calloc(1, pool->pagesize);
+ if (pool->alloc_block == NULL) {
+ return NULL;
+ }
+ if (!record_pool_block(&pool->pages, pool->alloc_block)) {
+ return NULL;
+ }
+ pool->next_page = pool->pages.num_blocks;
+ } else {
+ pool->alloc_block = pool->pages.blocklist[pool->next_page];
+ pool->next_page++;
+ }
+
+ pool->alloc_used = amount;
+
+ return pool->alloc_block;
+}
+
+void amqp_pool_alloc_bytes(amqp_pool_t *pool, size_t amount,
+ amqp_bytes_t *output) {
+ output->len = amount;
+ output->bytes = amqp_pool_alloc(pool, amount);
+}
+
+amqp_bytes_t amqp_cstring_bytes(char const *cstr) {
+ amqp_bytes_t result;
+ result.len = strlen(cstr);
+ result.bytes = (void *)cstr;
+ return result;
+}
+
+amqp_bytes_t amqp_bytes_malloc_dup(amqp_bytes_t src) {
+ amqp_bytes_t result;
+ result.len = src.len;
+ result.bytes = malloc(src.len);
+ if (result.bytes != NULL) {
+ memcpy(result.bytes, src.bytes, src.len);
+ }
+ return result;
+}
+
+amqp_bytes_t amqp_bytes_malloc(size_t amount) {
+ amqp_bytes_t result;
+ result.len = amount;
+ result.bytes = malloc(amount); /* will return NULL if it fails */
+ return result;
+}
+
+void amqp_bytes_free(amqp_bytes_t bytes) { free(bytes.bytes); }
+
+amqp_pool_t *amqp_get_or_create_channel_pool(amqp_connection_state_t state,
+ amqp_channel_t channel) {
+ amqp_pool_table_entry_t *entry;
+ size_t index = channel % POOL_TABLE_SIZE;
+
+ entry = state->pool_table[index];
+
+ for (; NULL != entry; entry = entry->next) {
+ if (channel == entry->channel) {
+ return &entry->pool;
+ }
+ }
+
+ entry = malloc(sizeof(amqp_pool_table_entry_t));
+ if (NULL == entry) {
+ return NULL;
+ }
+
+ entry->channel = channel;
+ entry->next = state->pool_table[index];
+ state->pool_table[index] = entry;
+
+ init_amqp_pool(&entry->pool, state->frame_max);
+
+ return &entry->pool;
+}
+
+amqp_pool_t *amqp_get_channel_pool(amqp_connection_state_t state,
+ amqp_channel_t channel) {
+ amqp_pool_table_entry_t *entry;
+ size_t index = channel % POOL_TABLE_SIZE;
+
+ entry = state->pool_table[index];
+
+ for (; NULL != entry; entry = entry->next) {
+ if (channel == entry->channel) {
+ return &entry->pool;
+ }
+ }
+
+ return NULL;
+}
+
+int amqp_bytes_equal(amqp_bytes_t r, amqp_bytes_t l) {
+ if (r.len == l.len &&
+ (r.bytes == l.bytes || 0 == memcmp(r.bytes, l.bytes, r.len))) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_openssl.c b/ext/librabbitmq/librabbitmq/amqp_openssl.c
new file mode 100644
index 000000000..bcd5ba53d
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_openssl.c
@@ -0,0 +1,704 @@
+/*
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2014 Alan Antonuk.
+ * All Rights Reserved.
+ *
+ * Portions created by Michael Steinert are Copyright (c) 2012-2014 Michael
+ * Steinert. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "amqp_openssl_bio.h"
+#include "amqp_openssl_hostname_validation.h"
+#include "amqp_private.h"
+#include "amqp_socket.h"
+#include "amqp_ssl_socket.h"
+#include "amqp_time.h"
+#include "threads.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int initialize_ssl_and_increment_connections(void);
+static int decrement_ssl_connections(void);
+
+static unsigned long ssl_threadid_callback(void);
+static void ssl_locking_callback(int mode, int n, const char *file, int line);
+static pthread_mutex_t *amqp_openssl_lockarray = NULL;
+
+static pthread_mutex_t openssl_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+static amqp_boolean_t do_initialize_openssl = 1;
+static amqp_boolean_t openssl_initialized = 0;
+static amqp_boolean_t openssl_bio_initialized = 0;
+static int openssl_connections = 0;
+
+#define CHECK_SUCCESS(condition) \
+ do { \
+ int check_success_ret = (condition); \
+ if (check_success_ret) { \
+ amqp_abort("Check %s failed <%d>: %s", #condition, check_success_ret, \
+ strerror(check_success_ret)); \
+ } \
+ } while (0)
+
+struct amqp_ssl_socket_t {
+ const struct amqp_socket_class_t *klass;
+ SSL_CTX *ctx;
+ int sockfd;
+ SSL *ssl;
+ amqp_boolean_t verify_peer;
+ amqp_boolean_t verify_hostname;
+ int internal_error;
+};
+
+static ssize_t amqp_ssl_socket_send(void *base, const void *buf, size_t len,
+ AMQP_UNUSED int flags) {
+ struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
+ int res;
+ if (-1 == self->sockfd) {
+ return AMQP_STATUS_SOCKET_CLOSED;
+ }
+
+ /* SSL_write takes an int for length of buffer, protect against len being
+ * larger than larger than what SSL_write can take */
+ if (len > INT_MAX) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+
+ ERR_clear_error();
+ self->internal_error = 0;
+
+ /* This will only return on error, or once the whole buffer has been
+ * written to the SSL stream. See SSL_MODE_ENABLE_PARTIAL_WRITE */
+ res = SSL_write(self->ssl, buf, (int)len);
+ if (0 >= res) {
+ self->internal_error = SSL_get_error(self->ssl, res);
+ /* TODO: Close connection if it isn't already? */
+ /* TODO: Possibly be more intelligent in reporting WHAT went wrong */
+ switch (self->internal_error) {
+ case SSL_ERROR_WANT_READ:
+ res = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ res = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ res = AMQP_STATUS_CONNECTION_CLOSED;
+ break;
+ default:
+ res = AMQP_STATUS_SSL_ERROR;
+ break;
+ }
+ } else {
+ self->internal_error = 0;
+ }
+
+ return (ssize_t)res;
+}
+
+static ssize_t amqp_ssl_socket_recv(void *base, void *buf, size_t len,
+ AMQP_UNUSED int flags) {
+ struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
+ int received;
+ if (-1 == self->sockfd) {
+ return AMQP_STATUS_SOCKET_CLOSED;
+ }
+
+ /* SSL_read takes an int for length of buffer, protect against len being
+ * larger than larger than what SSL_read can take */
+ if (len > INT_MAX) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+
+ ERR_clear_error();
+ self->internal_error = 0;
+
+ received = SSL_read(self->ssl, buf, (int)len);
+ if (0 >= received) {
+ self->internal_error = SSL_get_error(self->ssl, received);
+ switch (self->internal_error) {
+ case SSL_ERROR_WANT_READ:
+ received = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ received = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ received = AMQP_STATUS_CONNECTION_CLOSED;
+ break;
+ default:
+ received = AMQP_STATUS_SSL_ERROR;
+ break;
+ }
+ }
+
+ return (ssize_t)received;
+}
+
+static int amqp_ssl_socket_open(void *base, const char *host, int port,
+ struct timeval *timeout) {
+ struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
+ long result;
+ int status;
+ amqp_time_t deadline;
+ X509 *cert;
+ BIO *bio;
+ if (-1 != self->sockfd) {
+ return AMQP_STATUS_SOCKET_INUSE;
+ }
+ ERR_clear_error();
+
+ self->ssl = SSL_new(self->ctx);
+ if (!self->ssl) {
+ self->internal_error = ERR_peek_error();
+ status = AMQP_STATUS_SSL_ERROR;
+ goto exit;
+ }
+
+ status = amqp_time_from_now(&deadline, timeout);
+ if (AMQP_STATUS_OK != status) {
+ return status;
+ }
+
+ self->sockfd = amqp_open_socket_inner(host, port, deadline);
+ if (0 > self->sockfd) {
+ status = self->sockfd;
+ self->internal_error = amqp_os_socket_error();
+ self->sockfd = -1;
+ goto error_out1;
+ }
+
+ bio = BIO_new(amqp_openssl_bio());
+ if (!bio) {
+ status = AMQP_STATUS_NO_MEMORY;
+ goto error_out2;
+ }
+
+ BIO_set_fd(bio, self->sockfd, BIO_NOCLOSE);
+ SSL_set_bio(self->ssl, bio, bio);
+
+ status = SSL_set_tlsext_host_name(self->ssl, host);
+ if (!status) {
+ self->internal_error = SSL_get_error(self->ssl, status);
+ status = AMQP_STATUS_SSL_ERROR;
+ goto error_out2;
+ }
+
+start_connect:
+ status = SSL_connect(self->ssl);
+ if (status != 1) {
+ self->internal_error = SSL_get_error(self->ssl, status);
+ switch (self->internal_error) {
+ case SSL_ERROR_WANT_READ:
+ status = amqp_poll(self->sockfd, AMQP_SF_POLLIN, deadline);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ status = amqp_poll(self->sockfd, AMQP_SF_POLLOUT, deadline);
+ break;
+ default:
+ status = AMQP_STATUS_SSL_CONNECTION_FAILED;
+ }
+ if (AMQP_STATUS_OK == status) {
+ goto start_connect;
+ }
+ goto error_out2;
+ }
+
+ cert = SSL_get_peer_certificate(self->ssl);
+
+ if (self->verify_peer) {
+ if (!cert) {
+ self->internal_error = 0;
+ status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED;
+ goto error_out3;
+ }
+
+ result = SSL_get_verify_result(self->ssl);
+ if (X509_V_OK != result) {
+ self->internal_error = result;
+ status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED;
+ goto error_out4;
+ }
+ }
+ if (self->verify_hostname) {
+ if (!cert) {
+ self->internal_error = 0;
+ status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED;
+ goto error_out3;
+ }
+
+ if (AMQP_HVR_MATCH_FOUND != amqp_ssl_validate_hostname(host, cert)) {
+ self->internal_error = 0;
+ status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED;
+ goto error_out4;
+ }
+ }
+
+ X509_free(cert);
+ self->internal_error = 0;
+ status = AMQP_STATUS_OK;
+
+exit:
+ return status;
+
+error_out4:
+ X509_free(cert);
+error_out3:
+ SSL_shutdown(self->ssl);
+error_out2:
+ amqp_os_socket_close(self->sockfd);
+ self->sockfd = -1;
+error_out1:
+ SSL_free(self->ssl);
+ self->ssl = NULL;
+ goto exit;
+}
+
+static int amqp_ssl_socket_close(void *base, amqp_socket_close_enum force) {
+ struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
+
+ if (-1 == self->sockfd) {
+ return AMQP_STATUS_SOCKET_CLOSED;
+ }
+
+ if (AMQP_SC_NONE == force) {
+ /* don't try too hard to shutdown the connection */
+ SSL_shutdown(self->ssl);
+ }
+
+ SSL_free(self->ssl);
+ self->ssl = NULL;
+
+ if (amqp_os_socket_close(self->sockfd)) {
+ return AMQP_STATUS_SOCKET_ERROR;
+ }
+ self->sockfd = -1;
+
+ return AMQP_STATUS_OK;
+}
+
+static int amqp_ssl_socket_get_sockfd(void *base) {
+ struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
+ return self->sockfd;
+}
+
+static void amqp_ssl_socket_delete(void *base) {
+ struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
+
+ if (self) {
+ amqp_ssl_socket_close(self, AMQP_SC_NONE);
+
+ SSL_CTX_free(self->ctx);
+ free(self);
+ }
+ decrement_ssl_connections();
+}
+
+static const struct amqp_socket_class_t amqp_ssl_socket_class = {
+ amqp_ssl_socket_send, /* send */
+ amqp_ssl_socket_recv, /* recv */
+ amqp_ssl_socket_open, /* open */
+ amqp_ssl_socket_close, /* close */
+ amqp_ssl_socket_get_sockfd, /* get_sockfd */
+ amqp_ssl_socket_delete /* delete */
+};
+
+amqp_socket_t *amqp_ssl_socket_new(amqp_connection_state_t state) {
+ struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self));
+ int status;
+ if (!self) {
+ return NULL;
+ }
+
+ self->sockfd = -1;
+ self->klass = &amqp_ssl_socket_class;
+ self->verify_peer = 1;
+ self->verify_hostname = 1;
+
+ status = initialize_ssl_and_increment_connections();
+ if (status) {
+ goto error;
+ }
+
+ self->ctx = SSL_CTX_new(SSLv23_client_method());
+ if (!self->ctx) {
+ goto error;
+ }
+ /* Disable SSLv2 and SSLv3 */
+ SSL_CTX_set_options(self->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+
+ amqp_set_socket(state, (amqp_socket_t *)self);
+
+ return (amqp_socket_t *)self;
+error:
+ amqp_ssl_socket_delete((amqp_socket_t *)self);
+ return NULL;
+}
+
+int amqp_ssl_socket_set_cacert(amqp_socket_t *base, const char *cacert) {
+ int status;
+ struct amqp_ssl_socket_t *self;
+ if (base->klass != &amqp_ssl_socket_class) {
+ amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
+ }
+ self = (struct amqp_ssl_socket_t *)base;
+ status = SSL_CTX_load_verify_locations(self->ctx, cacert, NULL);
+ if (1 != status) {
+ return AMQP_STATUS_SSL_ERROR;
+ }
+ return AMQP_STATUS_OK;
+}
+
+int amqp_ssl_socket_set_key(amqp_socket_t *base, const char *cert,
+ const char *key) {
+ int status;
+ struct amqp_ssl_socket_t *self;
+ if (base->klass != &amqp_ssl_socket_class) {
+ amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
+ }
+ self = (struct amqp_ssl_socket_t *)base;
+ status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
+ if (1 != status) {
+ return AMQP_STATUS_SSL_ERROR;
+ }
+ status = SSL_CTX_use_PrivateKey_file(self->ctx, key, SSL_FILETYPE_PEM);
+ if (1 != status) {
+ return AMQP_STATUS_SSL_ERROR;
+ }
+ return AMQP_STATUS_OK;
+}
+
+static int password_cb(AMQP_UNUSED char *buffer, AMQP_UNUSED int length,
+ AMQP_UNUSED int rwflag, AMQP_UNUSED void *user_data) {
+ amqp_abort("rabbitmq-c does not support password protected keys");
+}
+
+int amqp_ssl_socket_set_key_buffer(amqp_socket_t *base, const char *cert,
+ const void *key, size_t n) {
+ int status = AMQP_STATUS_OK;
+ BIO *buf = NULL;
+ RSA *rsa = NULL;
+ struct amqp_ssl_socket_t *self;
+ if (base->klass != &amqp_ssl_socket_class) {
+ amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
+ }
+ if (n > INT_MAX) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+ self = (struct amqp_ssl_socket_t *)base;
+ status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
+ if (1 != status) {
+ return AMQP_STATUS_SSL_ERROR;
+ }
+ buf = BIO_new_mem_buf((void *)key, (int)n);
+ if (!buf) {
+ goto error;
+ }
+ rsa = PEM_read_bio_RSAPrivateKey(buf, NULL, password_cb, NULL);
+ if (!rsa) {
+ goto error;
+ }
+ status = SSL_CTX_use_RSAPrivateKey(self->ctx, rsa);
+ if (1 != status) {
+ goto error;
+ }
+exit:
+ BIO_vfree(buf);
+ RSA_free(rsa);
+ return status;
+error:
+ status = AMQP_STATUS_SSL_ERROR;
+ goto exit;
+}
+
+int amqp_ssl_socket_set_cert(amqp_socket_t *base, const char *cert) {
+ int status;
+ struct amqp_ssl_socket_t *self;
+ if (base->klass != &amqp_ssl_socket_class) {
+ amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
+ }
+ self = (struct amqp_ssl_socket_t *)base;
+ status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
+ if (1 != status) {
+ return AMQP_STATUS_SSL_ERROR;
+ }
+ return AMQP_STATUS_OK;
+}
+
+void amqp_ssl_socket_set_verify(amqp_socket_t *base, amqp_boolean_t verify) {
+ amqp_ssl_socket_set_verify_peer(base, verify);
+ amqp_ssl_socket_set_verify_hostname(base, verify);
+}
+
+void amqp_ssl_socket_set_verify_peer(amqp_socket_t *base,
+ amqp_boolean_t verify) {
+ struct amqp_ssl_socket_t *self;
+ if (base->klass != &amqp_ssl_socket_class) {
+ amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
+ }
+ self = (struct amqp_ssl_socket_t *)base;
+ self->verify_peer = verify;
+}
+
+void amqp_ssl_socket_set_verify_hostname(amqp_socket_t *base,
+ amqp_boolean_t verify) {
+ struct amqp_ssl_socket_t *self;
+ if (base->klass != &amqp_ssl_socket_class) {
+ amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
+ }
+ self = (struct amqp_ssl_socket_t *)base;
+ self->verify_hostname = verify;
+}
+
+int amqp_ssl_socket_set_ssl_versions(amqp_socket_t *base,
+ amqp_tls_version_t min,
+ amqp_tls_version_t max) {
+ struct amqp_ssl_socket_t *self;
+ if (base->klass != &amqp_ssl_socket_class) {
+ amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
+ }
+ self = (struct amqp_ssl_socket_t *)base;
+
+ {
+ long clear_options;
+ long set_options = 0;
+#if defined(SSL_OP_NO_TLSv1_2)
+ amqp_tls_version_t max_supported = AMQP_TLSv1_2;
+ clear_options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
+#elif defined(SSL_OP_NO_TLSv1_1)
+ amqp_tls_version_t max_supported = AMQP_TLSv1_1;
+ clear_options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
+#elif defined(SSL_OP_NO_TLSv1)
+ amqp_tls_version_t max_supported = AMQP_TLSv1;
+ clear_options = SSL_OP_NO_TLSv1;
+#else
+#error "Need a version of OpenSSL that can support TLSv1 or greater."
+#endif
+
+ if (AMQP_TLSvLATEST == max) {
+ max = max_supported;
+ }
+ if (AMQP_TLSvLATEST == min) {
+ min = max_supported;
+ }
+
+ if (min > max) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+
+ if (max > max_supported || min > max_supported) {
+ return AMQP_STATUS_UNSUPPORTED;
+ }
+
+ if (min > AMQP_TLSv1) {
+ set_options |= SSL_OP_NO_TLSv1;
+ }
+#ifdef SSL_OP_NO_TLSv1_1
+ if (min > AMQP_TLSv1_1 || max < AMQP_TLSv1_1) {
+ set_options |= SSL_OP_NO_TLSv1_1;
+ }
+#endif
+#ifdef SSL_OP_NO_TLSv1_2
+ if (max < AMQP_TLSv1_2) {
+ set_options |= SSL_OP_NO_TLSv1_2;
+ }
+#endif
+ SSL_CTX_clear_options(self->ctx, clear_options);
+ SSL_CTX_set_options(self->ctx, set_options);
+ }
+
+ return AMQP_STATUS_OK;
+}
+
+void amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize) {
+ CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
+
+ if (openssl_connections == 0 && !openssl_initialized) {
+ do_initialize_openssl = do_initialize;
+ }
+ CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
+}
+
+static unsigned long ssl_threadid_callback(void) {
+ return (unsigned long)pthread_self();
+}
+
+static void ssl_locking_callback(int mode, int n, AMQP_UNUSED const char *file,
+ AMQP_UNUSED int line) {
+ if (mode & CRYPTO_LOCK) {
+ CHECK_SUCCESS(pthread_mutex_lock(&amqp_openssl_lockarray[n]));
+ } else {
+ CHECK_SUCCESS(pthread_mutex_unlock(&amqp_openssl_lockarray[n]));
+ }
+}
+
+static int setup_openssl(void) {
+ int status;
+
+ int i;
+ amqp_openssl_lockarray = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t));
+ if (!amqp_openssl_lockarray) {
+ status = AMQP_STATUS_NO_MEMORY;
+ goto out;
+ }
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ if (pthread_mutex_init(&amqp_openssl_lockarray[i], NULL)) {
+ int j;
+ for (j = 0; j < i; j++) {
+ pthread_mutex_destroy(&amqp_openssl_lockarray[j]);
+ }
+ free(amqp_openssl_lockarray);
+ status = AMQP_STATUS_SSL_ERROR;
+ goto out;
+ }
+ }
+ CRYPTO_set_id_callback(ssl_threadid_callback);
+ CRYPTO_set_locking_callback(ssl_locking_callback);
+
+#ifdef AMQP_OPENSSL_V110
+ if (CONF_modules_load_file(NULL, "rabbitmq-c", CONF_MFLAGS_DEFAULT_SECTION) <=
+ 0) {
+ status = AMQP_STATUS_SSL_ERROR;
+ goto out;
+ }
+#else
+ OPENSSL_config(NULL);
+#endif
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ status = AMQP_STATUS_OK;
+out:
+ return status;
+}
+
+int amqp_initialize_ssl_library(void) {
+ int status;
+ CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
+
+ if (!openssl_initialized) {
+ status = setup_openssl();
+ if (status) {
+ goto out;
+ }
+ openssl_initialized = 1;
+ }
+
+ status = AMQP_STATUS_OK;
+out:
+ CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
+ return status;
+}
+
+static int initialize_ssl_and_increment_connections() {
+ int status;
+ CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
+
+ if (do_initialize_openssl && !openssl_initialized) {
+ status = setup_openssl();
+ if (status) {
+ goto exit;
+ }
+ openssl_initialized = 1;
+ }
+
+ if (!openssl_bio_initialized) {
+ status = amqp_openssl_bio_init();
+ if (status) {
+ goto exit;
+ }
+ openssl_bio_initialized = 1;
+ }
+
+ openssl_connections += 1;
+ status = AMQP_STATUS_OK;
+exit:
+ CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
+ return status;
+}
+
+static int decrement_ssl_connections(void) {
+ CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
+
+ if (openssl_connections > 0) {
+ openssl_connections--;
+ }
+
+ CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
+ return AMQP_STATUS_OK;
+}
+
+int amqp_uninitialize_ssl_library(void) {
+ int status;
+ CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
+
+ if (openssl_connections > 0) {
+ status = AMQP_STATUS_SOCKET_INUSE;
+ goto out;
+ }
+
+ amqp_openssl_bio_destroy();
+ openssl_bio_initialized = 0;
+
+#ifndef AMQP_OPENSSL_V110
+ ERR_remove_state(0);
+#endif
+
+#ifndef LIBRESSL_VERSION_NUMBER
+ FIPS_mode_set(0);
+#endif
+
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_id_callback(NULL);
+ {
+ int i;
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_destroy(&amqp_openssl_lockarray[i]);
+ }
+ free(amqp_openssl_lockarray);
+ }
+
+ ENGINE_cleanup();
+ CONF_modules_free();
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
+#if (OPENSSL_VERSION_NUMBER >= 0x10002003L) && !defined(LIBRESSL_VERSION_NUMBER)
+ SSL_COMP_free_compression_methods();
+#endif
+
+ openssl_initialized = 0;
+
+ status = AMQP_STATUS_OK;
+out:
+ CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
+ return status;
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_openssl_bio.c b/ext/librabbitmq/librabbitmq/amqp_openssl_bio.c
new file mode 100644
index 000000000..3556d6f3a
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_openssl_bio.c
@@ -0,0 +1,193 @@
+/*
+ * Portions created by Alan Antonuk are Copyright (c) 2017 Alan Antonuk.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "amqp_openssl_bio.h"
+#include "amqp_socket.h"
+
+#include
+#include
+#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+#else
+#include
+#include
+#endif
+
+#ifdef MSG_NOSIGNAL
+#define AMQP_USE_AMQP_BIO
+#endif
+
+static int amqp_ssl_bio_initialized = 0;
+
+#ifdef AMQP_USE_AMQP_BIO
+
+static BIO_METHOD *amqp_bio_method;
+
+static int amqp_openssl_bio_should_retry(int res) {
+ if (res == -1) {
+ int err = amqp_os_socket_error();
+ if (
+#ifdef EWOULDBLOCK
+ err == EWOULDBLOCK ||
+#endif
+#ifdef WSAEWOULDBLOCK
+ err == WSAEWOULDBLOCK ||
+#endif
+#ifdef ENOTCONN
+ err == ENOTCONN ||
+#endif
+#ifdef EINTR
+ err == EINTR ||
+#endif
+#ifdef EAGAIN
+ err == EAGAIN ||
+#endif
+#ifdef EPROTO
+ err == EPROTO ||
+#endif
+#ifdef EINPROGRESS
+ err == EINPROGRESS ||
+#endif
+#ifdef EALREADY
+ err == EALREADY ||
+#endif
+ 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int amqp_openssl_bio_write(BIO *b, const char *in, int inl) {
+ int flags = 0;
+ int fd;
+ int res;
+
+#ifdef MSG_NOSIGNAL
+ flags |= MSG_NOSIGNAL;
+#endif
+
+ BIO_get_fd(b, &fd);
+ res = send(fd, in, inl, flags);
+
+ BIO_clear_retry_flags(b);
+ if (res <= 0 && amqp_openssl_bio_should_retry(res)) {
+ BIO_set_retry_write(b);
+ }
+
+ return res;
+}
+
+static int amqp_openssl_bio_read(BIO *b, char *out, int outl) {
+ int flags = 0;
+ int fd;
+ int res;
+
+#ifdef MSG_NOSIGNAL
+ flags |= MSG_NOSIGNAL;
+#endif
+
+ BIO_get_fd(b, &fd);
+ res = recv(fd, out, outl, flags);
+
+ BIO_clear_retry_flags(b);
+ if (res <= 0 && amqp_openssl_bio_should_retry(res)) {
+ BIO_set_retry_read(b);
+ }
+
+ return res;
+}
+
+#ifndef AMQP_OPENSSL_V110
+static int BIO_meth_set_write(BIO_METHOD *biom,
+ int (*wfn)(BIO *, const char *, int)) {
+ biom->bwrite = wfn;
+ return 0;
+}
+
+static int BIO_meth_set_read(BIO_METHOD *biom, int (*rfn)(BIO *, char *, int)) {
+ biom->bread = rfn;
+ return 0;
+}
+#endif /* AQP_OPENSSL_V110 */
+#endif /* AMQP_USE_AMQP_BIO */
+
+int amqp_openssl_bio_init(void) {
+ assert(!amqp_ssl_bio_initialized);
+#ifdef AMQP_USE_AMQP_BIO
+#ifdef AMQP_OPENSSL_V110
+ if (!(amqp_bio_method = BIO_meth_new(BIO_TYPE_SOCKET, "amqp_bio_method"))) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ // casting away const is necessary until
+ // https://github.com/openssl/openssl/pull/2181/, which is targeted for
+ // openssl 1.1.1
+ BIO_METHOD *meth = (BIO_METHOD *)BIO_s_socket();
+ BIO_meth_set_create(amqp_bio_method, BIO_meth_get_create(meth));
+ BIO_meth_set_destroy(amqp_bio_method, BIO_meth_get_destroy(meth));
+ BIO_meth_set_ctrl(amqp_bio_method, BIO_meth_get_ctrl(meth));
+ BIO_meth_set_callback_ctrl(amqp_bio_method, BIO_meth_get_callback_ctrl(meth));
+ BIO_meth_set_read(amqp_bio_method, BIO_meth_get_read(meth));
+ BIO_meth_set_write(amqp_bio_method, BIO_meth_get_write(meth));
+ BIO_meth_set_gets(amqp_bio_method, BIO_meth_get_gets(meth));
+ BIO_meth_set_puts(amqp_bio_method, BIO_meth_get_puts(meth));
+#else
+ if (!(amqp_bio_method = OPENSSL_malloc(sizeof(BIO_METHOD)))) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ memcpy(amqp_bio_method, BIO_s_socket(), sizeof(BIO_METHOD));
+#endif
+ BIO_meth_set_write(amqp_bio_method, amqp_openssl_bio_write);
+ BIO_meth_set_read(amqp_bio_method, amqp_openssl_bio_read);
+#endif
+
+ amqp_ssl_bio_initialized = 1;
+ return AMQP_STATUS_OK;
+}
+
+void amqp_openssl_bio_destroy(void) {
+ assert(amqp_ssl_bio_initialized);
+#ifdef AMQP_USE_AMQP_BIO
+#ifdef AMQP_OPENSSL_V110
+ BIO_meth_free(amqp_bio_method);
+#else
+ OPENSSL_free(amqp_bio_method);
+#endif
+ amqp_bio_method = NULL;
+#endif
+ amqp_ssl_bio_initialized = 0;
+}
+
+BIO_METHOD_PTR amqp_openssl_bio(void) {
+ assert(amqp_ssl_bio_initialized);
+#ifdef AMQP_USE_AMQP_BIO
+ return amqp_bio_method;
+#else
+ return BIO_s_socket();
+#endif
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_openssl_bio.h b/ext/librabbitmq/librabbitmq/amqp_openssl_bio.h
new file mode 100644
index 000000000..ec09c5e7a
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_openssl_bio.h
@@ -0,0 +1,44 @@
+/*
+ * Portions created by Alan Antonuk are Copyright (c) 2017 Alan Antonuk.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef AMQP_OPENSSL_BIO
+#define AMQP_OPENSSL_BIO
+
+#include
+
+int amqp_openssl_bio_init(void);
+
+void amqp_openssl_bio_destroy(void);
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#define AMQP_OPENSSL_V110
+#endif
+
+#ifdef AMQP_OPENSSL_V110
+typedef const BIO_METHOD *BIO_METHOD_PTR;
+#else
+typedef BIO_METHOD *BIO_METHOD_PTR;
+#endif
+
+BIO_METHOD_PTR amqp_openssl_bio(void);
+
+#endif /* ifndef AMQP_OPENSSL_BIO */
diff --git a/ext/librabbitmq/librabbitmq/amqp_openssl_hostname_validation.c b/ext/librabbitmq/librabbitmq/amqp_openssl_hostname_validation.c
new file mode 100644
index 000000000..133d73c89
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_openssl_hostname_validation.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2012, iSEC Partners.
+ * Copyright (C) 2015 Alan Antonuk.
+ *
+ * All rights reserved.
+ *
+ * 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", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization of the
+ * copyright holder.
+ */
+
+/* Originally from:
+ * https://github.com/iSECPartners/ssl-conservatory
+ * https://wiki.openssl.org/index.php/Hostname_validation
+ */
+
+#include
+#include
+
+#include "amqp_hostcheck.h"
+#include "amqp_openssl_bio.h"
+#include "amqp_openssl_hostname_validation.h"
+
+#include
+
+#define HOSTNAME_MAX_SIZE 255
+
+/**
+ * Tries to find a match for hostname in the certificate's Common Name field.
+ *
+ * Returns AMQP_HVR_MATCH_FOUND if a match was found.
+ * Returns AMQP_HVR_MATCH_NOT_FOUND if no matches were found.
+ * Returns AMQP_HVR_MALFORMED_CERTIFICATE if the Common Name had a NUL character
+ * embedded in it.
+ * Returns AMQP_HVR_ERROR if the Common Name could not be extracted.
+ */
+static amqp_hostname_validation_result amqp_matches_common_name(
+ const char *hostname, const X509 *server_cert) {
+ int common_name_loc = -1;
+ X509_NAME_ENTRY *common_name_entry = NULL;
+ ASN1_STRING *common_name_asn1 = NULL;
+ const char *common_name_str = NULL;
+
+ // Find the position of the CN field in the Subject field of the certificate
+ common_name_loc = X509_NAME_get_index_by_NID(
+ X509_get_subject_name((X509 *)server_cert), NID_commonName, -1);
+ if (common_name_loc < 0) {
+ return AMQP_HVR_ERROR;
+ }
+
+ // Extract the CN field
+ common_name_entry = X509_NAME_get_entry(
+ X509_get_subject_name((X509 *)server_cert), common_name_loc);
+ if (common_name_entry == NULL) {
+ return AMQP_HVR_ERROR;
+ }
+
+ // Convert the CN field to a C string
+ common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
+ if (common_name_asn1 == NULL) {
+ return AMQP_HVR_ERROR;
+ }
+
+#ifdef AMQP_OPENSSL_V110
+ common_name_str = (const char *)ASN1_STRING_get0_data(common_name_asn1);
+#else
+ common_name_str = (char *)ASN1_STRING_data(common_name_asn1);
+#endif
+
+ // Make sure there isn't an embedded NUL character in the CN
+ if ((size_t)ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) {
+ return AMQP_HVR_MALFORMED_CERTIFICATE;
+ }
+
+ // Compare expected hostname with the CN
+ if (amqp_hostcheck(common_name_str, hostname) == AMQP_HCR_MATCH) {
+ return AMQP_HVR_MATCH_FOUND;
+ } else {
+ return AMQP_HVR_MATCH_NOT_FOUND;
+ }
+}
+
+/**
+ * Tries to find a match for hostname in the certificate's Subject Alternative
+ * Name extension.
+ *
+ * Returns AMQP_HVR_MATCH_FOUND if a match was found.
+ * Returns AMQP_HVR_MATCH_NOT_FOUND if no matches were found.
+ * Returns AMQP_HVR_MALFORMED_CERTIFICATE if any of the hostnames had a NUL
+ * character embedded in it.
+ * Returns AMQP_HVR_NO_SAN_PRESENT if the SAN extension was not present in the
+ * certificate.
+ */
+static amqp_hostname_validation_result amqp_matches_subject_alternative_name(
+ const char *hostname, const X509 *server_cert) {
+ amqp_hostname_validation_result result = AMQP_HVR_MATCH_NOT_FOUND;
+ int i;
+ int san_names_nb = -1;
+ STACK_OF(GENERAL_NAME) *san_names = NULL;
+
+ // Try to extract the names within the SAN extension from the certificate
+ san_names =
+ X509_get_ext_d2i((X509 *)server_cert, NID_subject_alt_name, NULL, NULL);
+ if (san_names == NULL) {
+ return AMQP_HVR_NO_SAN_PRESENT;
+ }
+ san_names_nb = sk_GENERAL_NAME_num(san_names);
+
+ // Check each name within the extension
+ for (i = 0; i < san_names_nb; i++) {
+ const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);
+
+ if (current_name->type == GEN_DNS) {
+ // Current name is a DNS name, let's check it
+ const char *dns_name = (const char *)
+#ifdef AMQP_OPENSSL_V110
+ ASN1_STRING_get0_data(current_name->d.dNSName);
+#else
+ ASN1_STRING_data(current_name->d.dNSName);
+#endif
+
+ // Make sure there isn't an embedded NUL character in the DNS name
+ if ((size_t)ASN1_STRING_length(current_name->d.dNSName) !=
+ strlen(dns_name)) {
+ result = AMQP_HVR_MALFORMED_CERTIFICATE;
+ break;
+ } else { // Compare expected hostname with the DNS name
+ if (amqp_hostcheck(dns_name, hostname) == AMQP_HCR_MATCH) {
+ result = AMQP_HVR_MATCH_FOUND;
+ break;
+ }
+ }
+ }
+ }
+ sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+
+ return result;
+}
+
+/**
+ * Validates the server's identity by looking for the expected hostname in the
+ * server's certificate. As described in RFC 6125, it first tries to find a
+ * match in the Subject Alternative Name extension. If the extension is not
+ * present in the certificate, it checks the Common Name instead.
+ *
+ * Returns AMQP_HVR_MATCH_FOUND if a match was found.
+ * Returns AMQP_HVR_MATCH_NOT_FOUND if no matches were found.
+ * Returns AMQP_HVR_MALFORMED_CERTIFICATE if any of the hostnames had a NUL
+ * character embedded in it.
+ * Returns AMQP_HVR_ERROR if there was an error.
+ */
+amqp_hostname_validation_result amqp_ssl_validate_hostname(
+ const char *hostname, const X509 *server_cert) {
+ amqp_hostname_validation_result result;
+
+ if ((hostname == NULL) || (server_cert == NULL)) return AMQP_HVR_ERROR;
+
+ // First try the Subject Alternative Names extension
+ result = amqp_matches_subject_alternative_name(hostname, server_cert);
+ if (result == AMQP_HVR_NO_SAN_PRESENT) {
+ // Extension was not found: try the Common Name
+ result = amqp_matches_common_name(hostname, server_cert);
+ }
+
+ return result;
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_openssl_hostname_validation.h b/ext/librabbitmq/librabbitmq/amqp_openssl_hostname_validation.h
new file mode 100644
index 000000000..c99487117
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_openssl_hostname_validation.h
@@ -0,0 +1,58 @@
+#ifndef librabbitmq_amqp_openssl_hostname_validation_h
+#define librabbitmq_amqp_openssl_hostname_validation_h
+
+/*
+ * Copyright (C) 2012, iSEC Partners.
+ * Copyright (C) 2015 Alan Antonuk.
+ *
+ * All rights reserved.
+ *
+ * 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", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization of the
+ * copyright holder.
+ */
+
+/* Originally from:
+ * https://github.com/iSECPartners/ssl-conservatory
+ * https://wiki.openssl.org/index.php/Hostname_validation
+ */
+
+#include
+
+typedef enum {
+ AMQP_HVR_MATCH_FOUND,
+ AMQP_HVR_MATCH_NOT_FOUND,
+ AMQP_HVR_NO_SAN_PRESENT,
+ AMQP_HVR_MALFORMED_CERTIFICATE,
+ AMQP_HVR_ERROR
+} amqp_hostname_validation_result;
+
+/**
+* Validates the server's identity by looking for the expected hostname in the
+* server's certificate. As described in RFC 6125, it first tries to find a match
+* in the Subject Alternative Name extension. If the extension is not present in
+* the certificate, it checks the Common Name instead.
+*
+* Returns AMQP_HVR_MATCH_FOUND if a match was found.
+* Returns AMQP_HVR_MATCH_NOT_FOUND if no matches were found.
+* Returns AMQP_HVR_MALFORMED_CERTIFICATE if any of the hostnames had a NUL
+* character embedded in it.
+* Returns AMQP_HVR_ERROR if there was an error.
+*/
+amqp_hostname_validation_result amqp_ssl_validate_hostname(
+ const char *hostname, const X509 *server_cert);
+
+#endif
diff --git a/ext/librabbitmq/librabbitmq/amqp_private.h b/ext/librabbitmq/librabbitmq/amqp_private.h
new file mode 100644
index 000000000..e73776c7d
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_private.h
@@ -0,0 +1,374 @@
+#ifndef librabbitmq_amqp_private_h
+#define librabbitmq_amqp_private_h
+
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2014
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define AMQ_COPYRIGHT \
+ "Copyright (c) 2007-2014 VMWare Inc, Tony Garnock-Jones," \
+ " and Alan Antonuk."
+
+#include "amqp.h"
+#include "amqp_framing.h"
+#include
+
+#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
+#ifndef WINVER
+/* WINVER 0x0502 is WinXP SP2+, Windows Server 2003 SP1+
+ * See:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa383745(v=vs.85).aspx#macros_for_conditional_declarations
+ */
+#define WINVER 0x0502
+#endif
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+#else
+#include
+#include
+#endif
+
+/* GCC attributes */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define AMQP_NORETURN __attribute__((__noreturn__))
+#define AMQP_UNUSED __attribute__((__unused__))
+#elif defined(_MSC_VER)
+#define AMQP_NORETURN __declspec(noreturn)
+#define AMQP_UNUSED
+#else
+#define AMQP_NORETURN
+#define AMQP_UNUSED
+#endif
+
+#if __GNUC__ >= 4
+#define AMQP_PRIVATE __attribute__((visibility("hidden")))
+#else
+#define AMQP_PRIVATE
+#endif
+
+char *amqp_os_error_string(int err);
+
+#ifdef WITH_SSL
+char *amqp_ssl_error_string(int err);
+#endif
+
+#include "amqp_socket.h"
+#include "amqp_time.h"
+
+/*
+ * Connection states: XXX FIX THIS
+ *
+ * - CONNECTION_STATE_INITIAL: The initial state, when we cannot be
+ * sure if the next thing we will get is the first AMQP frame, or a
+ * protocol header from the server.
+ *
+ * - CONNECTION_STATE_IDLE: The normal state between
+ * frames. Connections may only be reconfigured, and the
+ * connection's pools recycled, when in this state. Whenever we're
+ * in this state, the inbound_buffer's bytes pointer must be NULL;
+ * any other state, and it must point to a block of memory allocated
+ * from the frame_pool.
+ *
+ * - CONNECTION_STATE_HEADER: Some bytes of an incoming frame have
+ * been seen, but not a complete frame header's worth.
+ *
+ * - CONNECTION_STATE_BODY: A complete frame header has been seen, but
+ * the frame is not yet complete. When it is completed, it will be
+ * returned, and the connection will return to IDLE state.
+ *
+ */
+typedef enum amqp_connection_state_enum_ {
+ CONNECTION_STATE_IDLE = 0,
+ CONNECTION_STATE_INITIAL,
+ CONNECTION_STATE_HEADER,
+ CONNECTION_STATE_BODY
+} amqp_connection_state_enum;
+
+typedef enum amqp_status_private_enum_ {
+ /* 0x00xx -> AMQP_STATUS_*/
+ /* 0x01xx -> AMQP_STATUS_TCP_* */
+ /* 0x02xx -> AMQP_STATUS_SSL_* */
+ AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD = -0x1301,
+ AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE = -0x1302
+} amqp_status_private_enum;
+
+/* 7 bytes up front, then payload, then 1 byte footer */
+#define HEADER_SIZE 7
+#define FOOTER_SIZE 1
+
+#define AMQP_PSEUDOFRAME_PROTOCOL_HEADER 'A'
+
+typedef struct amqp_link_t_ {
+ struct amqp_link_t_ *next;
+ void *data;
+} amqp_link_t;
+
+#define POOL_TABLE_SIZE 16
+
+typedef struct amqp_pool_table_entry_t_ {
+ struct amqp_pool_table_entry_t_ *next;
+ amqp_pool_t pool;
+ amqp_channel_t channel;
+} amqp_pool_table_entry_t;
+
+struct amqp_connection_state_t_ {
+ amqp_pool_table_entry_t *pool_table[POOL_TABLE_SIZE];
+
+ amqp_connection_state_enum state;
+
+ int channel_max;
+ int frame_max;
+
+ /* Heartbeat interval in seconds. If this is <= 0, then heartbeats are not
+ * enabled, and next_recv_heartbeat and next_send_heartbeat are set to
+ * infinite */
+ int heartbeat;
+ amqp_time_t next_recv_heartbeat;
+ amqp_time_t next_send_heartbeat;
+
+ /* buffer for holding frame headers. Allows us to delay allocating
+ * the raw frame buffer until the type, channel, and size are all known
+ */
+ char header_buffer[HEADER_SIZE + 1];
+ amqp_bytes_t inbound_buffer;
+
+ size_t inbound_offset;
+ size_t target_size;
+
+ amqp_bytes_t outbound_buffer;
+
+ amqp_socket_t *socket;
+
+ amqp_bytes_t sock_inbound_buffer;
+ size_t sock_inbound_offset;
+ size_t sock_inbound_limit;
+
+ amqp_link_t *first_queued_frame;
+ amqp_link_t *last_queued_frame;
+
+ amqp_rpc_reply_t most_recent_api_result;
+
+ amqp_table_t server_properties;
+ amqp_table_t client_properties;
+ amqp_pool_t properties_pool;
+
+ struct timeval *handshake_timeout;
+ struct timeval internal_handshake_timeout;
+ struct timeval *rpc_timeout;
+ struct timeval internal_rpc_timeout;
+};
+
+amqp_pool_t *amqp_get_or_create_channel_pool(amqp_connection_state_t connection,
+ amqp_channel_t channel);
+amqp_pool_t *amqp_get_channel_pool(amqp_connection_state_t state,
+ amqp_channel_t channel);
+
+static inline int amqp_heartbeat_send(amqp_connection_state_t state) {
+ return state->heartbeat;
+}
+
+static inline int amqp_heartbeat_recv(amqp_connection_state_t state) {
+ return 2 * state->heartbeat;
+}
+
+int amqp_try_recv(amqp_connection_state_t state);
+
+static inline void *amqp_offset(void *data, size_t offset) {
+ return (char *)data + offset;
+}
+
+/* This macro defines the encoding and decoding functions associated with a
+ simple type. */
+
+#define DECLARE_CODEC_BASE_TYPE(bits) \
+ \
+ static inline int amqp_encode_##bits(amqp_bytes_t encoded, size_t *offset, \
+ uint##bits##_t input) { \
+ size_t o = *offset; \
+ if ((*offset = o + bits / 8) <= encoded.len) { \
+ amqp_e##bits(input, amqp_offset(encoded.bytes, o)); \
+ return 1; \
+ } \
+ return 0; \
+ } \
+ \
+ static inline int amqp_decode_##bits(amqp_bytes_t encoded, size_t *offset, \
+ uint##bits##_t *output) { \
+ size_t o = *offset; \
+ if ((*offset = o + bits / 8) <= encoded.len) { \
+ *output = amqp_d##bits(amqp_offset(encoded.bytes, o)); \
+ return 1; \
+ } \
+ return 0; \
+ }
+
+static inline int is_bigendian(void) {
+ union {
+ uint32_t i;
+ char c[4];
+ } bint = {0x01020304};
+ return bint.c[0] == 1;
+}
+
+static inline void amqp_e8(uint8_t val, void *data) {
+ memcpy(data, &val, sizeof(val));
+}
+
+static inline uint8_t amqp_d8(void *data) {
+ uint8_t val;
+ memcpy(&val, data, sizeof(val));
+ return val;
+}
+
+static inline void amqp_e16(uint16_t val, void *data) {
+ if (!is_bigendian()) {
+ val = ((val & 0xFF00u) >> 8u) | ((val & 0x00FFu) << 8u);
+ }
+ memcpy(data, &val, sizeof(val));
+}
+
+static inline uint16_t amqp_d16(void *data) {
+ uint16_t val;
+ memcpy(&val, data, sizeof(val));
+ if (!is_bigendian()) {
+ val = ((val & 0xFF00u) >> 8u) | ((val & 0x00FFu) << 8u);
+ }
+ return val;
+}
+
+static inline void amqp_e32(uint32_t val, void *data) {
+ if (!is_bigendian()) {
+ val = ((val & 0xFF000000u) >> 24u) | ((val & 0x00FF0000u) >> 8u) |
+ ((val & 0x0000FF00u) << 8u) | ((val & 0x000000FFu) << 24u);
+ }
+ memcpy(data, &val, sizeof(val));
+}
+
+static inline uint32_t amqp_d32(void *data) {
+ uint32_t val;
+ memcpy(&val, data, sizeof(val));
+ if (!is_bigendian()) {
+ val = ((val & 0xFF000000u) >> 24u) | ((val & 0x00FF0000u) >> 8u) |
+ ((val & 0x0000FF00u) << 8u) | ((val & 0x000000FFu) << 24u);
+ }
+ return val;
+}
+
+static inline void amqp_e64(uint64_t val, void *data) {
+ if (!is_bigendian()) {
+ val = ((val & 0xFF00000000000000u) >> 56u) |
+ ((val & 0x00FF000000000000u) >> 40u) |
+ ((val & 0x0000FF0000000000u) >> 24u) |
+ ((val & 0x000000FF00000000u) >> 8u) |
+ ((val & 0x00000000FF000000u) << 8u) |
+ ((val & 0x0000000000FF0000u) << 24u) |
+ ((val & 0x000000000000FF00u) << 40u) |
+ ((val & 0x00000000000000FFu) << 56u);
+ }
+ memcpy(data, &val, sizeof(val));
+}
+
+static inline uint64_t amqp_d64(void *data) {
+ uint64_t val;
+ memcpy(&val, data, sizeof(val));
+ if (!is_bigendian()) {
+ val = ((val & 0xFF00000000000000u) >> 56u) |
+ ((val & 0x00FF000000000000u) >> 40u) |
+ ((val & 0x0000FF0000000000u) >> 24u) |
+ ((val & 0x000000FF00000000u) >> 8u) |
+ ((val & 0x00000000FF000000u) << 8u) |
+ ((val & 0x0000000000FF0000u) << 24u) |
+ ((val & 0x000000000000FF00u) << 40u) |
+ ((val & 0x00000000000000FFu) << 56u);
+ }
+ return val;
+}
+
+DECLARE_CODEC_BASE_TYPE(8)
+DECLARE_CODEC_BASE_TYPE(16)
+DECLARE_CODEC_BASE_TYPE(32)
+DECLARE_CODEC_BASE_TYPE(64)
+
+static inline int amqp_encode_bytes(amqp_bytes_t encoded, size_t *offset,
+ amqp_bytes_t input) {
+ size_t o = *offset;
+ /* The memcpy below has undefined behavior if the input is NULL. It is valid
+ * for a 0-length amqp_bytes_t to have .bytes == NULL. Thus we should check
+ * before encoding.
+ */
+ if (input.len == 0) {
+ return 1;
+ }
+ if ((*offset = o + input.len) <= encoded.len) {
+ memcpy(amqp_offset(encoded.bytes, o), input.bytes, input.len);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static inline int amqp_decode_bytes(amqp_bytes_t encoded, size_t *offset,
+ amqp_bytes_t *output, size_t len) {
+ size_t o = *offset;
+ if ((*offset = o + len) <= encoded.len) {
+ output->bytes = amqp_offset(encoded.bytes, o);
+ output->len = len;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+AMQP_NORETURN
+void amqp_abort(const char *fmt, ...);
+
+int amqp_bytes_equal(amqp_bytes_t r, amqp_bytes_t l);
+
+static inline amqp_rpc_reply_t amqp_rpc_reply_error(amqp_status_enum status) {
+ amqp_rpc_reply_t reply;
+ reply.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
+ reply.library_error = status;
+ return reply;
+}
+
+int amqp_send_frame_inner(amqp_connection_state_t state,
+ const amqp_frame_t *frame, int flags,
+ amqp_time_t deadline);
+#endif
diff --git a/ext/librabbitmq/librabbitmq/amqp_socket.c b/ext/librabbitmq/librabbitmq/amqp_socket.c
new file mode 100644
index 000000000..061192ea9
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_socket.c
@@ -0,0 +1,1492 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2014
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "amqp_private.h"
+#include "amqp_socket.h"
+#include "amqp_table.h"
+#include "amqp_time.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+#include
+#else
+#include
+/* On older BSD types.h must come before net includes */
+#include
+#include
+#ifdef HAVE_SELECT
+#include
+#endif
+#include
+#include
+#include
+#include
+#ifdef HAVE_POLL
+#include
+#endif
+#include
+#endif
+
+static int amqp_id_in_reply_list(amqp_method_number_t expected,
+ amqp_method_number_t *list);
+
+static int amqp_os_socket_init(void) {
+#ifdef _WIN32
+ static int called_wsastartup = 0;
+ if (!called_wsastartup) {
+ WSADATA data;
+ int res = WSAStartup(0x0202, &data);
+ if (res) {
+ return AMQP_STATUS_TCP_SOCKETLIB_INIT_ERROR;
+ }
+
+ called_wsastartup = 1;
+ }
+ return AMQP_STATUS_OK;
+
+#else
+ return AMQP_STATUS_OK;
+#endif
+}
+
+int amqp_os_socket_error(void) {
+#ifdef _WIN32
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+int amqp_os_socket_close(int sockfd) {
+#ifdef _WIN32
+ return closesocket(sockfd);
+#else
+ return close(sockfd);
+#endif
+}
+
+ssize_t amqp_socket_send(amqp_socket_t *self, const void *buf, size_t len,
+ int flags) {
+ assert(self);
+ assert(self->klass->send);
+ return self->klass->send(self, buf, len, flags);
+}
+
+ssize_t amqp_socket_recv(amqp_socket_t *self, void *buf, size_t len,
+ int flags) {
+ assert(self);
+ assert(self->klass->recv);
+ return self->klass->recv(self, buf, len, flags);
+}
+
+int amqp_socket_open(amqp_socket_t *self, const char *host, int port) {
+ assert(self);
+ assert(self->klass->open);
+ return self->klass->open(self, host, port, NULL);
+}
+
+int amqp_socket_open_noblock(amqp_socket_t *self, const char *host, int port,
+ struct timeval *timeout) {
+ assert(self);
+ assert(self->klass->open);
+ return self->klass->open(self, host, port, timeout);
+}
+
+int amqp_socket_close(amqp_socket_t *self, amqp_socket_close_enum force) {
+ assert(self);
+ assert(self->klass->close);
+ return self->klass->close(self, force);
+}
+
+void amqp_socket_delete(amqp_socket_t *self) {
+ if (self) {
+ assert(self->klass->delete);
+ self->klass->delete (self);
+ }
+}
+
+int amqp_socket_get_sockfd(amqp_socket_t *self) {
+ assert(self);
+ assert(self->klass->get_sockfd);
+ return self->klass->get_sockfd(self);
+}
+
+int amqp_poll(int fd, int event, amqp_time_t deadline) {
+#ifdef HAVE_POLL
+ struct pollfd pfd;
+ int res;
+ int timeout_ms;
+
+ /* Function should only ever be called with one of these two */
+ assert(event == AMQP_SF_POLLIN || event == AMQP_SF_POLLOUT);
+
+start_poll:
+ pfd.fd = fd;
+ switch (event) {
+ case AMQP_SF_POLLIN:
+ pfd.events = POLLIN;
+ break;
+ case AMQP_SF_POLLOUT:
+ pfd.events = POLLOUT;
+ break;
+ }
+
+ timeout_ms = amqp_time_ms_until(deadline);
+ if (-1 > timeout_ms) {
+ return timeout_ms;
+ }
+
+ res = poll(&pfd, 1, timeout_ms);
+
+ if (0 < res) {
+ /* TODO: optimize this a bit by returning the AMQP_STATUS_SOCKET_ERROR or
+ * equivalent when pdf.revent is POLLHUP or POLLERR, so an extra syscall
+ * doesn't need to be made. */
+ return AMQP_STATUS_OK;
+ } else if (0 == res) {
+ return AMQP_STATUS_TIMEOUT;
+ } else {
+ switch (amqp_os_socket_error()) {
+ case EINTR:
+ goto start_poll;
+ default:
+ return AMQP_STATUS_SOCKET_ERROR;
+ }
+ }
+ return AMQP_STATUS_OK;
+#elif defined(HAVE_SELECT)
+ fd_set fds;
+ fd_set exceptfds;
+ fd_set *exceptfdsp;
+ int res;
+ struct timeval tv;
+ struct timeval *tvp;
+
+ assert((0 != (event & AMQP_SF_POLLIN)) || (0 != (event & AMQP_SF_POLLOUT)));
+#ifndef _WIN32
+ /* On Win32 connect() failure is indicated through the exceptfds, it does not
+ * make any sense to allow POLLERR on any other platform or condition */
+ assert(0 == (event & AMQP_SF_POLLERR));
+#endif
+
+start_select:
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ if (event & AMQP_SF_POLLERR) {
+ FD_ZERO(&exceptfds);
+ FD_SET(fd, &exceptfds);
+ exceptfdsp = &exceptfds;
+ } else {
+ exceptfdsp = NULL;
+ }
+
+ res = amqp_time_tv_until(deadline, &tv, &tvp);
+ if (res != AMQP_STATUS_OK) {
+ return res;
+ }
+
+ if (event & AMQP_SF_POLLIN) {
+ res = select(fd + 1, &fds, NULL, exceptfdsp, tvp);
+ } else if (event & AMQP_SF_POLLOUT) {
+ res = select(fd + 1, NULL, &fds, exceptfdsp, tvp);
+ }
+
+ if (0 < res) {
+ return AMQP_STATUS_OK;
+ } else if (0 == res) {
+ return AMQP_STATUS_TIMEOUT;
+ } else {
+ switch (amqp_os_socket_error()) {
+ case EINTR:
+ goto start_select;
+ default:
+ return AMQP_STATUS_SOCKET_ERROR;
+ }
+ }
+#else
+#error "poll() or select() is needed to compile rabbitmq-c"
+#endif
+}
+
+static ssize_t do_poll(amqp_connection_state_t state, ssize_t res,
+ amqp_time_t deadline) {
+ int fd = amqp_get_sockfd(state);
+ if (-1 == fd) {
+ return AMQP_STATUS_SOCKET_CLOSED;
+ }
+ switch (res) {
+ case AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD:
+ res = amqp_poll(fd, AMQP_SF_POLLIN, deadline);
+ break;
+ case AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE:
+ res = amqp_poll(fd, AMQP_SF_POLLOUT, deadline);
+ break;
+ }
+ return res;
+}
+
+ssize_t amqp_try_send(amqp_connection_state_t state, const void *buf,
+ size_t len, amqp_time_t deadline, int flags) {
+ ssize_t res;
+ void *buf_left = (void *)buf;
+ /* Assume that len is not going to be larger than ssize_t can hold. */
+ ssize_t len_left = (size_t)len;
+
+start_send:
+ res = amqp_socket_send(state->socket, buf_left, len_left, flags);
+
+ if (res > 0) {
+ len_left -= res;
+ buf_left = (char *)buf_left + res;
+ if (0 == len_left) {
+ return (ssize_t)len;
+ }
+ goto start_send;
+ }
+ res = do_poll(state, res, deadline);
+ if (AMQP_STATUS_OK == res) {
+ goto start_send;
+ }
+ if (AMQP_STATUS_TIMEOUT == res) {
+ return (ssize_t)len - len_left;
+ }
+ return res;
+}
+
+int amqp_open_socket(char const *hostname, int portnumber) {
+ return amqp_open_socket_inner(hostname, portnumber, amqp_time_infinite());
+}
+
+int amqp_open_socket_noblock(char const *hostname, int portnumber,
+ struct timeval *timeout) {
+ amqp_time_t deadline;
+ int res = amqp_time_from_now(&deadline, timeout);
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+ return amqp_open_socket_inner(hostname, portnumber, deadline);
+}
+
+#ifdef _WIN32
+static int connect_socket(struct addrinfo *addr, amqp_time_t deadline) {
+ int one = 1;
+ SOCKET sockfd;
+ int last_error;
+
+ /*
+ * This cast is to squash warnings on Win64, see:
+ * http://stackoverflow.com/questions/1953639/is-it-safe-to-cast-socket-to-int-under-win64
+ */
+
+ sockfd = (int)socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+ if (INVALID_SOCKET == sockfd) {
+ return AMQP_STATUS_SOCKET_ERROR;
+ }
+
+ /* Set the socket to be non-blocking */
+ if (SOCKET_ERROR == ioctlsocket(sockfd, FIONBIO, &one)) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+
+ /* Disable nagle */
+ if (SOCKET_ERROR == setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
+ (const char *)&one, sizeof(one))) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+
+ /* Enable TCP keepalives */
+ if (SOCKET_ERROR == setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
+ (const char *)&one, sizeof(one))) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+
+ if (SOCKET_ERROR != connect(sockfd, addr->ai_addr, (int)addr->ai_addrlen)) {
+ return (int)sockfd;
+ }
+
+ if (WSAEWOULDBLOCK != WSAGetLastError()) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+
+ last_error =
+ amqp_poll((int)sockfd, AMQP_SF_POLLOUT | AMQP_SF_POLLERR, deadline);
+ if (AMQP_STATUS_OK != last_error) {
+ goto err;
+ }
+
+ {
+ int result;
+ int result_len = sizeof(result);
+
+ if (SOCKET_ERROR == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
+ (char *)&result, &result_len) ||
+ result != 0) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+ }
+
+ return (int)sockfd;
+
+err:
+ closesocket(sockfd);
+ return last_error;
+}
+#else
+static int connect_socket(struct addrinfo *addr, amqp_time_t deadline) {
+ int one = 1;
+ int sockfd;
+ int flags;
+ int last_error;
+
+ sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+ if (-1 == sockfd) {
+ return AMQP_STATUS_SOCKET_ERROR;
+ }
+
+ /* Enable CLOEXEC on socket */
+ flags = fcntl(sockfd, F_GETFD);
+ if (flags == -1 || fcntl(sockfd, F_SETFD, (long)(flags | FD_CLOEXEC)) == -1) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+
+ /* Set the socket as non-blocking */
+ flags = fcntl(sockfd, F_GETFL);
+ if (flags == -1 || fcntl(sockfd, F_SETFL, (long)(flags | O_NONBLOCK)) == -1) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+
+#ifdef SO_NOSIGPIPE
+ /* Turn off SIGPIPE on platforms that support it, BSD, MacOSX */
+ if (0 != setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one))) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+#endif /* SO_NOSIGPIPE */
+
+ /* Disable nagle */
+ if (0 != setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one))) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+
+ /* Enable TCP keepalives */
+ if (0 != setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one))) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+
+ if (0 == connect(sockfd, addr->ai_addr, addr->ai_addrlen)) {
+ return sockfd;
+ }
+
+ if (EINPROGRESS != errno) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+
+ last_error = amqp_poll(sockfd, AMQP_SF_POLLOUT, deadline);
+ if (AMQP_STATUS_OK != last_error) {
+ goto err;
+ }
+
+ {
+ int result;
+ socklen_t result_len = sizeof(result);
+
+ if (-1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &result, &result_len) ||
+ result != 0) {
+ last_error = AMQP_STATUS_SOCKET_ERROR;
+ goto err;
+ }
+ }
+
+ return sockfd;
+
+err:
+ close(sockfd);
+ return last_error;
+}
+#endif
+
+int amqp_open_socket_inner(char const *hostname, int portnumber,
+ amqp_time_t deadline) {
+ struct addrinfo hint;
+ struct addrinfo *address_list;
+ struct addrinfo *addr;
+ char portnumber_string[33];
+ int sockfd = -1;
+ int last_error;
+
+ last_error = amqp_os_socket_init();
+ if (AMQP_STATUS_OK != last_error) {
+ return last_error;
+ }
+
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = PF_UNSPEC; /* PF_INET or PF_INET6 */
+ hint.ai_socktype = SOCK_STREAM;
+ hint.ai_protocol = IPPROTO_TCP;
+
+ (void)sprintf(portnumber_string, "%d", portnumber);
+
+ last_error = getaddrinfo(hostname, portnumber_string, &hint, &address_list);
+ if (0 != last_error) {
+ return AMQP_STATUS_HOSTNAME_RESOLUTION_FAILED;
+ }
+
+ for (addr = address_list; addr; addr = addr->ai_next) {
+ sockfd = connect_socket(addr, deadline);
+
+ if (sockfd >= 0) {
+ last_error = AMQP_STATUS_OK;
+ break;
+ } else if (sockfd == AMQP_STATUS_TIMEOUT) {
+ last_error = sockfd;
+ break;
+ }
+ }
+
+ freeaddrinfo(address_list);
+ if (last_error != AMQP_STATUS_OK || sockfd == -1) {
+ return last_error;
+ }
+ return sockfd;
+}
+
+static int send_header_inner(amqp_connection_state_t state,
+ amqp_time_t deadline) {
+ ssize_t res;
+ static const uint8_t header[8] = {'A',
+ 'M',
+ 'Q',
+ 'P',
+ 0,
+ AMQP_PROTOCOL_VERSION_MAJOR,
+ AMQP_PROTOCOL_VERSION_MINOR,
+ AMQP_PROTOCOL_VERSION_REVISION};
+ res = amqp_try_send(state, header, sizeof(header), deadline, AMQP_SF_NONE);
+ if (sizeof(header) == res) {
+ return AMQP_STATUS_OK;
+ }
+ return (int)res;
+}
+
+int amqp_send_header(amqp_connection_state_t state) {
+ return send_header_inner(state, amqp_time_infinite());
+}
+
+static amqp_bytes_t sasl_method_name(amqp_sasl_method_enum method) {
+ amqp_bytes_t res;
+
+ switch (method) {
+ case AMQP_SASL_METHOD_PLAIN:
+ res = amqp_cstring_bytes("PLAIN");
+ break;
+ case AMQP_SASL_METHOD_EXTERNAL:
+ res = amqp_cstring_bytes("EXTERNAL");
+ break;
+
+ default:
+ amqp_abort("Invalid SASL method: %d", (int)method);
+ }
+
+ return res;
+}
+
+static int bytes_equal(amqp_bytes_t l, amqp_bytes_t r) {
+ if (l.len == r.len) {
+ if (l.bytes && r.bytes) {
+ if (0 == memcmp(l.bytes, r.bytes, l.len)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int sasl_mechanism_in_list(amqp_bytes_t mechanisms,
+ amqp_sasl_method_enum method) {
+ amqp_bytes_t mechanism;
+ amqp_bytes_t supported_mechanism;
+ uint8_t *start;
+ uint8_t *end;
+ uint8_t *current;
+
+ assert(NULL != mechanisms.bytes);
+
+ mechanism = sasl_method_name(method);
+
+ start = (uint8_t *)mechanisms.bytes;
+ current = start;
+ end = start + mechanisms.len;
+
+ for (; current != end; start = current + 1) {
+ /* HACK: SASL states that we should be parsing this string as a UTF-8
+ * string, which we're plainly not doing here. At this point its not worth
+ * dragging an entire UTF-8 parser for this one case, and this should work
+ * most of the time */
+ current = memchr(start, ' ', end - start);
+ if (NULL == current) {
+ current = end;
+ }
+ supported_mechanism.bytes = start;
+ supported_mechanism.len = current - start;
+ if (bytes_equal(mechanism, supported_mechanism)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static amqp_bytes_t sasl_response(amqp_pool_t *pool,
+ amqp_sasl_method_enum method, va_list args) {
+ amqp_bytes_t response;
+
+ switch (method) {
+ case AMQP_SASL_METHOD_PLAIN: {
+ char *username = va_arg(args, char *);
+ size_t username_len = strlen(username);
+ char *password = va_arg(args, char *);
+ size_t password_len = strlen(password);
+ char *response_buf;
+
+ amqp_pool_alloc_bytes(pool, strlen(username) + strlen(password) + 2,
+ &response);
+ if (response.bytes == NULL)
+ /* We never request a zero-length block, because of the +2
+ above, so a NULL here really is ENOMEM. */
+ {
+ return response;
+ }
+
+ response_buf = response.bytes;
+ response_buf[0] = 0;
+ memcpy(response_buf + 1, username, username_len);
+ response_buf[username_len + 1] = 0;
+ memcpy(response_buf + username_len + 2, password, password_len);
+ break;
+ }
+ case AMQP_SASL_METHOD_EXTERNAL: {
+ char *identity = va_arg(args, char *);
+ size_t identity_len = strlen(identity);
+
+ amqp_pool_alloc_bytes(pool, identity_len, &response);
+ if (response.bytes == NULL) {
+ return response;
+ }
+
+ memcpy(response.bytes, identity, identity_len);
+ break;
+ }
+ default:
+ amqp_abort("Invalid SASL method: %d", (int)method);
+ }
+
+ return response;
+}
+
+amqp_boolean_t amqp_frames_enqueued(amqp_connection_state_t state) {
+ return (state->first_queued_frame != NULL);
+}
+
+/*
+ * Check to see if we have data in our buffer. If this returns 1, we
+ * will avoid an immediate blocking read in amqp_simple_wait_frame.
+ */
+amqp_boolean_t amqp_data_in_buffer(amqp_connection_state_t state) {
+ return (state->sock_inbound_offset < state->sock_inbound_limit);
+}
+
+static int consume_one_frame(amqp_connection_state_t state,
+ amqp_frame_t *decoded_frame) {
+ int res;
+
+ amqp_bytes_t buffer;
+ buffer.len = state->sock_inbound_limit - state->sock_inbound_offset;
+ buffer.bytes =
+ ((char *)state->sock_inbound_buffer.bytes) + state->sock_inbound_offset;
+
+ res = amqp_handle_input(state, buffer, decoded_frame);
+ if (res < 0) {
+ return res;
+ }
+
+ state->sock_inbound_offset += res;
+
+ return AMQP_STATUS_OK;
+}
+
+static int recv_with_timeout(amqp_connection_state_t state,
+ amqp_time_t timeout) {
+ ssize_t res;
+ int fd;
+
+start_recv:
+ res = amqp_socket_recv(state->socket, state->sock_inbound_buffer.bytes,
+ state->sock_inbound_buffer.len, 0);
+
+ if (res < 0) {
+ fd = amqp_get_sockfd(state);
+ if (-1 == fd) {
+ return AMQP_STATUS_CONNECTION_CLOSED;
+ }
+ switch (res) {
+ default:
+ return (int)res;
+ case AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD:
+ res = amqp_poll(fd, AMQP_SF_POLLIN, timeout);
+ break;
+ case AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE:
+ res = amqp_poll(fd, AMQP_SF_POLLOUT, timeout);
+ break;
+ }
+ if (AMQP_STATUS_OK == res) {
+ goto start_recv;
+ }
+ return (int)res;
+ }
+
+ state->sock_inbound_limit = res;
+ state->sock_inbound_offset = 0;
+
+ res = amqp_time_s_from_now(&state->next_recv_heartbeat,
+ amqp_heartbeat_recv(state));
+ if (AMQP_STATUS_OK != res) {
+ return (int)res;
+ }
+ return AMQP_STATUS_OK;
+}
+
+int amqp_try_recv(amqp_connection_state_t state) {
+ amqp_time_t timeout;
+
+ while (amqp_data_in_buffer(state)) {
+ amqp_frame_t frame;
+ int res = consume_one_frame(state, &frame);
+
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+
+ if (frame.frame_type != 0) {
+ amqp_pool_t *channel_pool;
+ amqp_frame_t *frame_copy;
+ amqp_link_t *link;
+
+ channel_pool = amqp_get_or_create_channel_pool(state, frame.channel);
+ if (NULL == channel_pool) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ frame_copy = amqp_pool_alloc(channel_pool, sizeof(amqp_frame_t));
+ link = amqp_pool_alloc(channel_pool, sizeof(amqp_link_t));
+
+ if (frame_copy == NULL || link == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ *frame_copy = frame;
+
+ link->next = NULL;
+ link->data = frame_copy;
+
+ if (state->last_queued_frame == NULL) {
+ state->first_queued_frame = link;
+ } else {
+ state->last_queued_frame->next = link;
+ }
+ state->last_queued_frame = link;
+ }
+ }
+ timeout = amqp_time_immediate();
+
+ return recv_with_timeout(state, timeout);
+}
+
+static int wait_frame_inner(amqp_connection_state_t state,
+ amqp_frame_t *decoded_frame,
+ amqp_time_t timeout_deadline) {
+ amqp_time_t deadline;
+ int res;
+
+ for (;;) {
+ while (amqp_data_in_buffer(state)) {
+ res = consume_one_frame(state, decoded_frame);
+
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+
+ if (AMQP_FRAME_HEARTBEAT == decoded_frame->frame_type) {
+ amqp_maybe_release_buffers_on_channel(state, 0);
+ continue;
+ }
+
+ if (decoded_frame->frame_type != 0) {
+ /* Complete frame was read. Return it. */
+ return AMQP_STATUS_OK;
+ }
+ }
+
+ beginrecv:
+ res = amqp_time_has_past(state->next_send_heartbeat);
+ if (AMQP_STATUS_TIMER_FAILURE == res) {
+ return res;
+ } else if (AMQP_STATUS_TIMEOUT == res) {
+ amqp_frame_t heartbeat;
+ heartbeat.channel = 0;
+ heartbeat.frame_type = AMQP_FRAME_HEARTBEAT;
+
+ res = amqp_send_frame(state, &heartbeat);
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+ }
+ deadline = amqp_time_first(timeout_deadline,
+ amqp_time_first(state->next_recv_heartbeat,
+ state->next_send_heartbeat));
+
+ /* TODO this needs to wait for a _frame_ and not anything written from the
+ * socket */
+ res = recv_with_timeout(state, deadline);
+
+ if (AMQP_STATUS_TIMEOUT == res) {
+ if (amqp_time_equal(deadline, state->next_recv_heartbeat)) {
+ amqp_socket_close(state->socket, AMQP_SC_FORCE);
+ return AMQP_STATUS_HEARTBEAT_TIMEOUT;
+ } else if (amqp_time_equal(deadline, timeout_deadline)) {
+ return AMQP_STATUS_TIMEOUT;
+ } else if (amqp_time_equal(deadline, state->next_send_heartbeat)) {
+ /* send heartbeat happens before we do recv_with_timeout */
+ goto beginrecv;
+ } else {
+ amqp_abort("Internal error: unable to determine timeout reason");
+ }
+ } else if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+ }
+}
+
+static amqp_link_t *amqp_create_link_for_frame(amqp_connection_state_t state,
+ amqp_frame_t *frame) {
+ amqp_link_t *link;
+ amqp_frame_t *frame_copy;
+
+ amqp_pool_t *channel_pool =
+ amqp_get_or_create_channel_pool(state, frame->channel);
+
+ if (NULL == channel_pool) {
+ return NULL;
+ }
+
+ link = amqp_pool_alloc(channel_pool, sizeof(amqp_link_t));
+ frame_copy = amqp_pool_alloc(channel_pool, sizeof(amqp_frame_t));
+
+ if (NULL == link || NULL == frame_copy) {
+ return NULL;
+ }
+
+ *frame_copy = *frame;
+ link->data = frame_copy;
+
+ return link;
+}
+
+int amqp_queue_frame(amqp_connection_state_t state, amqp_frame_t *frame) {
+ amqp_link_t *link = amqp_create_link_for_frame(state, frame);
+ if (NULL == link) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ if (NULL == state->first_queued_frame) {
+ state->first_queued_frame = link;
+ } else {
+ state->last_queued_frame->next = link;
+ }
+
+ link->next = NULL;
+ state->last_queued_frame = link;
+
+ return AMQP_STATUS_OK;
+}
+
+int amqp_put_back_frame(amqp_connection_state_t state, amqp_frame_t *frame) {
+ amqp_link_t *link = amqp_create_link_for_frame(state, frame);
+ if (NULL == link) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ if (NULL == state->first_queued_frame) {
+ state->first_queued_frame = link;
+ state->last_queued_frame = link;
+ link->next = NULL;
+ } else {
+ link->next = state->first_queued_frame;
+ state->first_queued_frame = link;
+ }
+
+ return AMQP_STATUS_OK;
+}
+
+int amqp_simple_wait_frame_on_channel(amqp_connection_state_t state,
+ amqp_channel_t channel,
+ amqp_frame_t *decoded_frame) {
+ amqp_frame_t *frame_ptr;
+ amqp_link_t *cur;
+ int res;
+
+ for (cur = state->first_queued_frame; NULL != cur; cur = cur->next) {
+ frame_ptr = cur->data;
+
+ if (channel == frame_ptr->channel) {
+ state->first_queued_frame = cur->next;
+ if (NULL == state->first_queued_frame) {
+ state->last_queued_frame = NULL;
+ }
+
+ *decoded_frame = *frame_ptr;
+
+ return AMQP_STATUS_OK;
+ }
+ }
+
+ for (;;) {
+ res = wait_frame_inner(state, decoded_frame, amqp_time_infinite());
+
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+
+ if (channel == decoded_frame->channel) {
+ return AMQP_STATUS_OK;
+ } else {
+ res = amqp_queue_frame(state, decoded_frame);
+ if (res != AMQP_STATUS_OK) {
+ return res;
+ }
+ }
+ }
+}
+
+int amqp_simple_wait_frame(amqp_connection_state_t state,
+ amqp_frame_t *decoded_frame) {
+ return amqp_simple_wait_frame_noblock(state, decoded_frame, NULL);
+}
+
+int amqp_simple_wait_frame_noblock(amqp_connection_state_t state,
+ amqp_frame_t *decoded_frame,
+ struct timeval *timeout) {
+ amqp_time_t deadline;
+
+ int res = amqp_time_from_now(&deadline, timeout);
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+
+ if (state->first_queued_frame != NULL) {
+ amqp_frame_t *f = (amqp_frame_t *)state->first_queued_frame->data;
+ state->first_queued_frame = state->first_queued_frame->next;
+ if (state->first_queued_frame == NULL) {
+ state->last_queued_frame = NULL;
+ }
+ *decoded_frame = *f;
+ return AMQP_STATUS_OK;
+ } else {
+ return wait_frame_inner(state, decoded_frame, deadline);
+ }
+}
+
+static int amqp_simple_wait_method_list(amqp_connection_state_t state,
+ amqp_channel_t expected_channel,
+ amqp_method_number_t *expected_methods,
+ amqp_time_t deadline,
+ amqp_method_t *output) {
+ amqp_frame_t frame;
+ struct timeval tv;
+ struct timeval *tvp;
+
+ int res = amqp_time_tv_until(deadline, &tv, &tvp);
+ if (res != AMQP_STATUS_OK) {
+ return res;
+ }
+
+ res = amqp_simple_wait_frame_noblock(state, &frame, tvp);
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+
+ if (AMQP_FRAME_METHOD != frame.frame_type ||
+ expected_channel != frame.channel ||
+ !amqp_id_in_reply_list(frame.payload.method.id, expected_methods)) {
+ return AMQP_STATUS_WRONG_METHOD;
+ }
+ *output = frame.payload.method;
+ return AMQP_STATUS_OK;
+}
+
+static int simple_wait_method_inner(amqp_connection_state_t state,
+ amqp_channel_t expected_channel,
+ amqp_method_number_t expected_method,
+ amqp_time_t deadline,
+ amqp_method_t *output) {
+ amqp_method_number_t expected_methods[] = {expected_method, 0};
+ return amqp_simple_wait_method_list(state, expected_channel, expected_methods,
+ deadline, output);
+}
+
+int amqp_simple_wait_method(amqp_connection_state_t state,
+ amqp_channel_t expected_channel,
+ amqp_method_number_t expected_method,
+ amqp_method_t *output) {
+ return simple_wait_method_inner(state, expected_channel, expected_method,
+ amqp_time_infinite(), output);
+}
+
+int amqp_send_method(amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_method_number_t id, void *decoded) {
+ return amqp_send_method_inner(state, channel, id, decoded, AMQP_SF_NONE,
+ amqp_time_infinite());
+}
+
+int amqp_send_method_inner(amqp_connection_state_t state,
+ amqp_channel_t channel, amqp_method_number_t id,
+ void *decoded, int flags, amqp_time_t deadline) {
+ amqp_frame_t frame;
+
+ frame.frame_type = AMQP_FRAME_METHOD;
+ frame.channel = channel;
+ frame.payload.method.id = id;
+ frame.payload.method.decoded = decoded;
+ return amqp_send_frame_inner(state, &frame, flags, deadline);
+}
+
+static int amqp_id_in_reply_list(amqp_method_number_t expected,
+ amqp_method_number_t *list) {
+ while (*list != 0) {
+ if (*list == expected) {
+ return 1;
+ }
+ list++;
+ }
+ return 0;
+}
+
+static amqp_rpc_reply_t simple_rpc_inner(
+ amqp_connection_state_t state, amqp_channel_t channel,
+ amqp_method_number_t request_id, amqp_method_number_t *expected_reply_ids,
+ void *decoded_request_method, amqp_time_t deadline) {
+ int status;
+ amqp_rpc_reply_t result;
+
+ memset(&result, 0, sizeof(result));
+
+ status = amqp_send_method(state, channel, request_id, decoded_request_method);
+ if (status < 0) {
+ return amqp_rpc_reply_error(status);
+ }
+
+ {
+ amqp_frame_t frame;
+
+ retry:
+ status = wait_frame_inner(state, &frame, deadline);
+ if (status < 0) {
+ if (status == AMQP_STATUS_TIMEOUT) {
+ amqp_socket_close(state->socket, AMQP_SC_FORCE);
+ }
+ return amqp_rpc_reply_error(status);
+ }
+
+ /*
+ * We store the frame for later processing unless it's something
+ * that directly affects us here, namely a method frame that is
+ * either
+ * - on the channel we want, and of the expected type, or
+ * - on the channel we want, and a channel.close frame, or
+ * - on channel zero, and a connection.close frame.
+ */
+ if (!((frame.frame_type == AMQP_FRAME_METHOD) &&
+ (((frame.channel == channel) &&
+ (amqp_id_in_reply_list(frame.payload.method.id,
+ expected_reply_ids) ||
+ (frame.payload.method.id == AMQP_CHANNEL_CLOSE_METHOD))) ||
+ ((frame.channel == 0) &&
+ (frame.payload.method.id == AMQP_CONNECTION_CLOSE_METHOD))))) {
+ amqp_pool_t *channel_pool;
+ amqp_frame_t *frame_copy;
+ amqp_link_t *link;
+
+ channel_pool = amqp_get_or_create_channel_pool(state, frame.channel);
+ if (NULL == channel_pool) {
+ return amqp_rpc_reply_error(AMQP_STATUS_NO_MEMORY);
+ }
+
+ frame_copy = amqp_pool_alloc(channel_pool, sizeof(amqp_frame_t));
+ link = amqp_pool_alloc(channel_pool, sizeof(amqp_link_t));
+
+ if (frame_copy == NULL || link == NULL) {
+ return amqp_rpc_reply_error(AMQP_STATUS_NO_MEMORY);
+ }
+
+ *frame_copy = frame;
+
+ link->next = NULL;
+ link->data = frame_copy;
+
+ if (state->last_queued_frame == NULL) {
+ state->first_queued_frame = link;
+ } else {
+ state->last_queued_frame->next = link;
+ }
+ state->last_queued_frame = link;
+
+ goto retry;
+ }
+
+ result.reply_type =
+ (amqp_id_in_reply_list(frame.payload.method.id, expected_reply_ids))
+ ? AMQP_RESPONSE_NORMAL
+ : AMQP_RESPONSE_SERVER_EXCEPTION;
+
+ result.reply = frame.payload.method;
+ return result;
+ }
+}
+
+amqp_rpc_reply_t amqp_simple_rpc(amqp_connection_state_t state,
+ amqp_channel_t channel,
+ amqp_method_number_t request_id,
+ amqp_method_number_t *expected_reply_ids,
+ void *decoded_request_method) {
+ amqp_time_t deadline;
+ int res;
+
+ res = amqp_time_from_now(&deadline, state->rpc_timeout);
+ if (res != AMQP_STATUS_OK) {
+ return amqp_rpc_reply_error(res);
+ }
+
+ return simple_rpc_inner(state, channel, request_id, expected_reply_ids,
+ decoded_request_method, deadline);
+}
+
+void *amqp_simple_rpc_decoded(amqp_connection_state_t state,
+ amqp_channel_t channel,
+ amqp_method_number_t request_id,
+ amqp_method_number_t reply_id,
+ void *decoded_request_method) {
+ amqp_time_t deadline;
+ int res;
+ amqp_method_number_t replies[2];
+
+ res = amqp_time_from_now(&deadline, state->rpc_timeout);
+ if (res != AMQP_STATUS_OK) {
+ state->most_recent_api_result = amqp_rpc_reply_error(res);
+ return NULL;
+ }
+
+ replies[0] = reply_id;
+ replies[1] = 0;
+
+ state->most_recent_api_result = simple_rpc_inner(
+ state, channel, request_id, replies, decoded_request_method, deadline);
+
+ if (state->most_recent_api_result.reply_type == AMQP_RESPONSE_NORMAL) {
+ return state->most_recent_api_result.reply.decoded;
+ } else {
+ return NULL;
+ }
+}
+
+amqp_rpc_reply_t amqp_get_rpc_reply(amqp_connection_state_t state) {
+ return state->most_recent_api_result;
+}
+
+/*
+ * Merge base and add tables. If the two tables contain an entry with the same
+ * key, the entry from the add table takes precedence. For entries that are both
+ * tables with the same key, the table is recursively merged.
+ */
+int amqp_merge_capabilities(const amqp_table_t *base, const amqp_table_t *add,
+ amqp_table_t *result, amqp_pool_t *pool) {
+ int i;
+ int res;
+ amqp_pool_t temp_pool;
+ amqp_table_t temp_result;
+ assert(base != NULL);
+ assert(result != NULL);
+ assert(pool != NULL);
+
+ if (NULL == add) {
+ return amqp_table_clone(base, result, pool);
+ }
+
+ init_amqp_pool(&temp_pool, 4096);
+ temp_result.num_entries = 0;
+ temp_result.entries =
+ amqp_pool_alloc(&temp_pool, sizeof(amqp_table_entry_t) *
+ (base->num_entries + add->num_entries));
+ if (NULL == temp_result.entries) {
+ res = AMQP_STATUS_NO_MEMORY;
+ goto error_out;
+ }
+ for (i = 0; i < base->num_entries; ++i) {
+ temp_result.entries[temp_result.num_entries] = base->entries[i];
+ temp_result.num_entries++;
+ }
+ for (i = 0; i < add->num_entries; ++i) {
+ amqp_table_entry_t *e =
+ amqp_table_get_entry_by_key(&temp_result, add->entries[i].key);
+ if (NULL != e) {
+ if (AMQP_FIELD_KIND_TABLE == add->entries[i].value.kind &&
+ AMQP_FIELD_KIND_TABLE == e->value.kind) {
+ amqp_table_entry_t *be =
+ amqp_table_get_entry_by_key(base, add->entries[i].key);
+
+ res = amqp_merge_capabilities(&be->value.value.table,
+ &add->entries[i].value.value.table,
+ &e->value.value.table, &temp_pool);
+ if (AMQP_STATUS_OK != res) {
+ goto error_out;
+ }
+ } else {
+ e->value = add->entries[i].value;
+ }
+ } else {
+ temp_result.entries[temp_result.num_entries] = add->entries[i];
+ temp_result.num_entries++;
+ }
+ }
+ res = amqp_table_clone(&temp_result, result, pool);
+error_out:
+ empty_amqp_pool(&temp_pool);
+ return res;
+}
+
+static amqp_rpc_reply_t amqp_login_inner(
+ amqp_connection_state_t state, char const *vhost, int channel_max,
+ int frame_max, int heartbeat, const amqp_table_t *client_properties,
+ struct timeval *timeout, amqp_sasl_method_enum sasl_method, va_list vl) {
+ int res;
+ amqp_method_t method;
+
+ uint16_t client_channel_max;
+ uint32_t client_frame_max;
+ uint16_t client_heartbeat;
+
+ uint16_t server_channel_max;
+ uint32_t server_frame_max;
+ uint16_t server_heartbeat;
+
+ amqp_rpc_reply_t result;
+ amqp_time_t deadline;
+
+ if (channel_max < 0 || channel_max > UINT16_MAX) {
+ return amqp_rpc_reply_error(AMQP_STATUS_INVALID_PARAMETER);
+ }
+ client_channel_max = (uint16_t)channel_max;
+
+ if (frame_max < 0) {
+ return amqp_rpc_reply_error(AMQP_STATUS_INVALID_PARAMETER);
+ }
+ client_frame_max = (uint32_t)frame_max;
+
+ if (heartbeat < 0 || heartbeat > UINT16_MAX) {
+ return amqp_rpc_reply_error(AMQP_STATUS_INVALID_PARAMETER);
+ }
+ client_heartbeat = (uint16_t)heartbeat;
+
+ res = amqp_time_from_now(&deadline, timeout);
+ if (AMQP_STATUS_OK != res) {
+ goto error_res;
+ }
+
+ res = send_header_inner(state, deadline);
+ if (AMQP_STATUS_OK != res) {
+ goto error_res;
+ }
+
+ res = simple_wait_method_inner(state, 0, AMQP_CONNECTION_START_METHOD,
+ deadline, &method);
+ if (AMQP_STATUS_OK != res) {
+ goto error_res;
+ }
+
+ {
+ amqp_connection_start_t *s = (amqp_connection_start_t *)method.decoded;
+ if ((s->version_major != AMQP_PROTOCOL_VERSION_MAJOR) ||
+ (s->version_minor != AMQP_PROTOCOL_VERSION_MINOR)) {
+ res = AMQP_STATUS_INCOMPATIBLE_AMQP_VERSION;
+ goto error_res;
+ }
+
+ res = amqp_table_clone(&s->server_properties, &state->server_properties,
+ &state->properties_pool);
+
+ if (AMQP_STATUS_OK != res) {
+ goto error_res;
+ }
+
+ /* TODO: check that our chosen SASL mechanism is in the list of
+ acceptable mechanisms. Or even let the application choose from
+ the list! */
+ if (!sasl_mechanism_in_list(s->mechanisms, sasl_method)) {
+ res = AMQP_STATUS_BROKER_UNSUPPORTED_SASL_METHOD;
+ goto error_res;
+ }
+ }
+
+ {
+ amqp_table_entry_t default_properties[6];
+ amqp_table_t default_table;
+ amqp_table_entry_t client_capabilities[2];
+ amqp_table_t client_capabilities_table;
+ amqp_connection_start_ok_t s;
+ amqp_pool_t *channel_pool;
+ amqp_bytes_t response_bytes;
+
+ channel_pool = amqp_get_or_create_channel_pool(state, 0);
+ if (NULL == channel_pool) {
+ res = AMQP_STATUS_NO_MEMORY;
+ goto error_res;
+ }
+
+ response_bytes = sasl_response(channel_pool, sasl_method, vl);
+ if (response_bytes.bytes == NULL) {
+ res = AMQP_STATUS_NO_MEMORY;
+ goto error_res;
+ }
+
+ client_capabilities[0] =
+ amqp_table_construct_bool_entry("authentication_failure_close", 1);
+ client_capabilities[1] =
+ amqp_table_construct_bool_entry("exchange_exchange_bindings", 1);
+
+ client_capabilities_table.entries = client_capabilities;
+ client_capabilities_table.num_entries =
+ sizeof(client_capabilities) / sizeof(amqp_table_entry_t);
+
+ default_properties[0] =
+ amqp_table_construct_utf8_entry("product", "rabbitmq-c");
+ default_properties[1] =
+ amqp_table_construct_utf8_entry("version", AMQP_VERSION_STRING);
+ default_properties[2] =
+ amqp_table_construct_utf8_entry("platform", AMQ_PLATFORM);
+ default_properties[3] =
+ amqp_table_construct_utf8_entry("copyright", AMQ_COPYRIGHT);
+ default_properties[4] = amqp_table_construct_utf8_entry(
+ "information", "See https://github.com/alanxz/rabbitmq-c");
+ default_properties[5] = amqp_table_construct_table_entry(
+ "capabilities", &client_capabilities_table);
+
+ default_table.entries = default_properties;
+ default_table.num_entries =
+ sizeof(default_properties) / sizeof(amqp_table_entry_t);
+
+ res = amqp_merge_capabilities(&default_table, client_properties,
+ &state->client_properties, channel_pool);
+ if (AMQP_STATUS_OK != res) {
+ goto error_res;
+ }
+
+ s.client_properties = state->client_properties;
+ s.mechanism = sasl_method_name(sasl_method);
+ s.response = response_bytes;
+ s.locale = amqp_cstring_bytes("en_US");
+
+ res = amqp_send_method_inner(state, 0, AMQP_CONNECTION_START_OK_METHOD, &s,
+ AMQP_SF_NONE, deadline);
+ if (res < 0) {
+ goto error_res;
+ }
+ }
+
+ amqp_release_buffers(state);
+
+ {
+ amqp_method_number_t expected[] = {AMQP_CONNECTION_TUNE_METHOD,
+ AMQP_CONNECTION_CLOSE_METHOD, 0};
+
+ res = amqp_simple_wait_method_list(state, 0, expected, deadline, &method);
+ if (AMQP_STATUS_OK != res) {
+ goto error_res;
+ }
+ }
+
+ if (AMQP_CONNECTION_CLOSE_METHOD == method.id) {
+ result.reply_type = AMQP_RESPONSE_SERVER_EXCEPTION;
+ result.reply = method;
+ result.library_error = 0;
+ goto out;
+ }
+
+ {
+ amqp_connection_tune_t *s = (amqp_connection_tune_t *)method.decoded;
+ server_channel_max = s->channel_max;
+ server_frame_max = s->frame_max;
+ server_heartbeat = s->heartbeat;
+ }
+
+ if (server_channel_max != 0 &&
+ (server_channel_max < client_channel_max || client_channel_max == 0)) {
+ client_channel_max = server_channel_max;
+ } else if (server_channel_max == 0 && client_channel_max == 0) {
+ client_channel_max = UINT16_MAX;
+ }
+
+ if (server_frame_max != 0 && server_frame_max < client_frame_max) {
+ client_frame_max = server_frame_max;
+ }
+
+ if (server_heartbeat != 0 && server_heartbeat < client_heartbeat) {
+ client_heartbeat = server_heartbeat;
+ }
+
+ res = amqp_tune_connection(state, client_channel_max, client_frame_max,
+ client_heartbeat);
+ if (res < 0) {
+ goto error_res;
+ }
+
+ {
+ amqp_connection_tune_ok_t s;
+ s.frame_max = client_frame_max;
+ s.channel_max = client_channel_max;
+ s.heartbeat = client_heartbeat;
+
+ res = amqp_send_method_inner(state, 0, AMQP_CONNECTION_TUNE_OK_METHOD, &s,
+ AMQP_SF_NONE, deadline);
+ if (res < 0) {
+ goto error_res;
+ }
+ }
+
+ amqp_release_buffers(state);
+
+ {
+ amqp_method_number_t replies[] = {AMQP_CONNECTION_OPEN_OK_METHOD, 0};
+ amqp_connection_open_t s;
+ s.virtual_host = amqp_cstring_bytes(vhost);
+ s.capabilities = amqp_empty_bytes;
+ s.insist = 1;
+
+ result = simple_rpc_inner(state, 0, AMQP_CONNECTION_OPEN_METHOD, replies,
+ &s, deadline);
+ if (result.reply_type != AMQP_RESPONSE_NORMAL) {
+ goto out;
+ }
+ }
+
+ result.reply_type = AMQP_RESPONSE_NORMAL;
+ result.reply.id = 0;
+ result.reply.decoded = NULL;
+ result.library_error = 0;
+ amqp_maybe_release_buffers(state);
+
+out:
+ return result;
+
+error_res:
+ amqp_socket_close(state->socket, AMQP_SC_FORCE);
+ result = amqp_rpc_reply_error(res);
+
+ goto out;
+}
+
+amqp_rpc_reply_t amqp_login(amqp_connection_state_t state, char const *vhost,
+ int channel_max, int frame_max, int heartbeat,
+ int sasl_method, ...) {
+ va_list vl;
+ amqp_rpc_reply_t ret;
+
+ va_start(vl, sasl_method);
+
+ ret = amqp_login_inner(state, vhost, channel_max, frame_max, heartbeat,
+ &amqp_empty_table, state->handshake_timeout,
+ sasl_method, vl);
+
+ va_end(vl);
+
+ return ret;
+}
+
+amqp_rpc_reply_t amqp_login_with_properties(
+ amqp_connection_state_t state, char const *vhost, int channel_max,
+ int frame_max, int heartbeat, const amqp_table_t *client_properties,
+ int sasl_method, ...) {
+ va_list vl;
+ amqp_rpc_reply_t ret;
+
+ va_start(vl, sasl_method);
+
+ ret = amqp_login_inner(state, vhost, channel_max, frame_max, heartbeat,
+ client_properties, state->handshake_timeout,
+ sasl_method, vl);
+
+ va_end(vl);
+
+ return ret;
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_socket.h b/ext/librabbitmq/librabbitmq/amqp_socket.h
new file mode 100644
index 000000000..3101cf605
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_socket.h
@@ -0,0 +1,188 @@
+/*
+ * Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
+ * All Rights Reserved.
+ *
+ * Portions created by Michael Steinert are Copyright (c) 2012-2013 Michael
+ * Steinert. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * An abstract socket interface.
+ */
+
+#ifndef AMQP_SOCKET_H
+#define AMQP_SOCKET_H
+
+#include "amqp_private.h"
+#include "amqp_time.h"
+
+AMQP_BEGIN_DECLS
+
+typedef enum {
+ AMQP_SF_NONE = 0,
+ AMQP_SF_MORE = 1,
+ AMQP_SF_POLLIN = 2,
+ AMQP_SF_POLLOUT = 4,
+ AMQP_SF_POLLERR = 8
+} amqp_socket_flag_enum;
+
+typedef enum { AMQP_SC_NONE = 0, AMQP_SC_FORCE = 1 } amqp_socket_close_enum;
+
+int amqp_os_socket_error(void);
+
+int amqp_os_socket_close(int sockfd);
+
+/* Socket callbacks. */
+typedef ssize_t (*amqp_socket_send_fn)(void *, const void *, size_t, int);
+typedef ssize_t (*amqp_socket_recv_fn)(void *, void *, size_t, int);
+typedef int (*amqp_socket_open_fn)(void *, const char *, int, struct timeval *);
+typedef int (*amqp_socket_close_fn)(void *, amqp_socket_close_enum);
+typedef int (*amqp_socket_get_sockfd_fn)(void *);
+typedef void (*amqp_socket_delete_fn)(void *);
+
+/** V-table for amqp_socket_t */
+struct amqp_socket_class_t {
+ amqp_socket_send_fn send;
+ amqp_socket_recv_fn recv;
+ amqp_socket_open_fn open;
+ amqp_socket_close_fn close;
+ amqp_socket_get_sockfd_fn get_sockfd;
+ amqp_socket_delete_fn delete;
+};
+
+/** Abstract base class for amqp_socket_t */
+struct amqp_socket_t_ {
+ const struct amqp_socket_class_t *klass;
+};
+
+/**
+ * Set set the socket object for a connection
+ *
+ * This assigns a socket object to the connection, closing and deleting any
+ * existing socket
+ *
+ * \param [in] state The connection object to add the socket to
+ * \param [in] socket The socket object to assign to the connection
+ */
+void amqp_set_socket(amqp_connection_state_t state, amqp_socket_t *socket);
+
+/**
+ * Send a message from a socket.
+ *
+ * This function wraps send(2) functionality.
+ *
+ * This function will only return on error, or when all of the bytes in buf
+ * have been sent, or when an error occurs.
+ *
+ * \param [in,out] self A socket object.
+ * \param [in] buf A buffer to read from.
+ * \param [in] len The number of bytes in \e buf.
+ * \param [in]
+ *
+ * \return AMQP_STATUS_OK on success. amqp_status_enum value otherwise
+ */
+ssize_t amqp_socket_send(amqp_socket_t *self, const void *buf, size_t len,
+ int flags);
+
+ssize_t amqp_try_send(amqp_connection_state_t state, const void *buf,
+ size_t len, amqp_time_t deadline, int flags);
+
+/**
+ * Receive a message from a socket.
+ *
+ * This function wraps recv(2) functionality.
+ *
+ * \param [in,out] self A socket object.
+ * \param [out] buf A buffer to write to.
+ * \param [in] len The number of bytes at \e buf.
+ * \param [in] flags Receive flags, implementation specific.
+ *
+ * \return The number of bytes received, or < 0 on error (\ref amqp_status_enum)
+ */
+ssize_t amqp_socket_recv(amqp_socket_t *self, void *buf, size_t len, int flags);
+
+/**
+ * Close a socket connection and free resources.
+ *
+ * This function closes a socket connection and releases any resources used by
+ * the object. After calling this function the specified socket should no
+ * longer be referenced.
+ *
+ * \param [in,out] self A socket object.
+ * \param [in] force, if set, just close the socket, don't attempt a TLS
+ * shutdown.
+ *
+ * \return Zero upon success, non-zero otherwise.
+ */
+int amqp_socket_close(amqp_socket_t *self, amqp_socket_close_enum force);
+
+/**
+ * Destroy a socket object
+ *
+ * \param [in] self the socket object to delete
+ */
+void amqp_socket_delete(amqp_socket_t *self);
+
+/**
+ * Open a socket connection.
+ *
+ * This function opens a socket connection returned from amqp_tcp_socket_new()
+ * or amqp_ssl_socket_new(). This function should be called after setting
+ * socket options and prior to assigning the socket to an AMQP connection with
+ * amqp_set_socket().
+ *
+ * \param [in] host Connect to this host.
+ * \param [in] port Connect on this remote port.
+ * \param [in] timeout Max allowed time to spent on opening. If NULL - run in
+ * blocking mode
+ *
+ * \return File descriptor upon success, non-zero negative error code otherwise.
+ */
+int amqp_open_socket_noblock(char const *hostname, int portnumber,
+ struct timeval *timeout);
+
+int amqp_open_socket_inner(char const *hostname, int portnumber,
+ amqp_time_t deadline);
+
+/* Wait up to dealline for fd to become readable or writeable depending on
+ * event (AMQP_SF_POLLIN, AMQP_SF_POLLOUT) */
+int amqp_poll(int fd, int event, amqp_time_t deadline);
+
+int amqp_send_method_inner(amqp_connection_state_t state,
+ amqp_channel_t channel, amqp_method_number_t id,
+ void *decoded, int flags, amqp_time_t deadline);
+
+int amqp_queue_frame(amqp_connection_state_t state, amqp_frame_t *frame);
+
+int amqp_put_back_frame(amqp_connection_state_t state, amqp_frame_t *frame);
+
+int amqp_simple_wait_frame_on_channel(amqp_connection_state_t state,
+ amqp_channel_t channel,
+ amqp_frame_t *decoded_frame);
+
+int sasl_mechanism_in_list(amqp_bytes_t mechanisms,
+ amqp_sasl_method_enum method);
+
+int amqp_merge_capabilities(const amqp_table_t *base, const amqp_table_t *add,
+ amqp_table_t *result, amqp_pool_t *pool);
+AMQP_END_DECLS
+
+#endif /* AMQP_SOCKET_H */
diff --git a/ext/librabbitmq/librabbitmq/amqp_ssl_socket.h b/ext/librabbitmq/librabbitmq/amqp_ssl_socket.h
new file mode 100644
index 000000000..9977ae4ba
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_ssl_socket.h
@@ -0,0 +1,239 @@
+/** \file */
+/*
+ * Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
+ * All Rights Reserved.
+ *
+ * Portions created by Michael Steinert are Copyright (c) 2012-2013 Michael
+ * Steinert. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef AMQP_SSL_H
+#define AMQP_SSL_H
+
+#include
+
+AMQP_BEGIN_DECLS
+
+/**
+ * Create a new SSL/TLS socket object.
+ *
+ * The returned socket object is owned by the \ref amqp_connection_state_t
+ * object and will be destroyed when the state object is destroyed or a new
+ * socket object is created.
+ *
+ * If the socket object creation fails, the \ref amqp_connection_state_t object
+ * will not be changed.
+ *
+ * The object returned by this function can be retrieved from the
+ * amqp_connection_state_t object later using the amqp_get_socket() function.
+ *
+ * Calling this function may result in the underlying SSL library being
+ * initialized.
+ * \sa amqp_set_initialize_ssl_library()
+ *
+ * \param [in,out] state The connection object that owns the SSL/TLS socket
+ * \return A new socket object or NULL if an error occurred.
+ *
+ * \since v0.4.0
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_socket_t *AMQP_CALL amqp_ssl_socket_new(amqp_connection_state_t state);
+
+/**
+ * Set the CA certificate.
+ *
+ * \param [in,out] self An SSL/TLS socket object.
+ * \param [in] cacert Path to the CA cert file in PEM format.
+ *
+ * \return \ref AMQP_STATUS_OK on success an \ref amqp_status_enum value on
+ * failure.
+ *
+ * \since v0.4.0
+ */
+AMQP_PUBLIC_FUNCTION
+int AMQP_CALL amqp_ssl_socket_set_cacert(amqp_socket_t *self,
+ const char *cacert);
+
+/**
+ * Set the client key.
+ *
+ * \param [in,out] self An SSL/TLS socket object.
+ * \param [in] cert Path to the client certificate in PEM foramt.
+ * \param [in] key Path to the client key in PEM format.
+ *
+ * \return \ref AMQP_STATUS_OK on success an \ref amqp_status_enum value on
+ * failure.
+ *
+ * \since v0.4.0
+ */
+AMQP_PUBLIC_FUNCTION
+int AMQP_CALL amqp_ssl_socket_set_key(amqp_socket_t *self, const char *cert,
+ const char *key);
+
+/**
+ * Set the client key from a buffer.
+ *
+ * \param [in,out] self An SSL/TLS socket object.
+ * \param [in] cert Path to the client certificate in PEM foramt.
+ * \param [in] key A buffer containing client key in PEM format.
+ * \param [in] n The length of the buffer.
+ *
+ * \return \ref AMQP_STATUS_OK on success an \ref amqp_status_enum value on
+ * failure.
+ *
+ * \since v0.4.0
+ */
+AMQP_PUBLIC_FUNCTION
+int AMQP_CALL amqp_ssl_socket_set_key_buffer(amqp_socket_t *self,
+ const char *cert, const void *key,
+ size_t n);
+
+/**
+ * Enable or disable peer verification.
+ *
+ * \deprecated use \amqp_ssl_socket_set_verify_peer and
+ * \amqp_ssl_socket_set_verify_hostname instead.
+ *
+ * If peer verification is enabled then the common name in the server
+ * certificate must match the server name. Peer verification is enabled by
+ * default.
+ *
+ * \param [in,out] self An SSL/TLS socket object.
+ * \param [in] verify Enable or disable peer verification.
+ *
+ * \since v0.4.0
+ */
+AMQP_DEPRECATED(AMQP_PUBLIC_FUNCTION void AMQP_CALL amqp_ssl_socket_set_verify(
+ amqp_socket_t *self, amqp_boolean_t verify));
+
+/**
+ * Enable or disable peer verification.
+ *
+ * Peer verification validates the certificate chain that is sent by the broker.
+ * Hostname validation is controlled by \amqp_ssl_socket_set_verify_peer.
+ *
+ * \param [in,out] self An SSL/TLS socket object.
+ * \param [in] verify enable or disable peer validation
+ *
+ * \since v0.8.0
+ */
+AMQP_PUBLIC_FUNCTION
+void AMQP_CALL amqp_ssl_socket_set_verify_peer(amqp_socket_t *self,
+ amqp_boolean_t verify);
+
+/**
+ * Enable or disable hostname verification.
+ *
+ * Hostname verification checks the broker cert for a CN or SAN that matches the
+ * hostname that amqp_socket_open() is presented. Peer verification is
+ * controlled by \amqp_ssl_socket_set_verify_peer
+ *
+ * \since v0.8.0
+ */
+AMQP_PUBLIC_FUNCTION
+void AMQP_CALL amqp_ssl_socket_set_verify_hostname(amqp_socket_t *self,
+ amqp_boolean_t verify);
+
+typedef enum {
+ AMQP_TLSv1 = 1,
+ AMQP_TLSv1_1 = 2,
+ AMQP_TLSv1_2 = 3,
+ AMQP_TLSvLATEST = 0xFFFF
+} amqp_tls_version_t;
+
+/**
+ * Set min and max TLS versions.
+ *
+ * Set the oldest and newest acceptable TLS versions that are acceptable when
+ * connecting to the broker. Set min == max to restrict to just that
+ * version.
+ *
+ * \param [in,out] self An SSL/TLS socket object.
+ * \param [in] min the minimum acceptable TLS version
+ * \param [in] max the maxmium acceptable TLS version
+ * \returns AMQP_STATUS_OK on success, AMQP_STATUS_UNSUPPORTED if OpenSSL does
+ * not support the requested TLS version, AMQP_STATUS_INVALID_PARAMETER if an
+ * invalid combination of parameters is passed.
+ *
+ * \since v0.8.0
+ */
+AMQP_PUBLIC_FUNCTION
+int AMQP_CALL amqp_ssl_socket_set_ssl_versions(amqp_socket_t *self,
+ amqp_tls_version_t min,
+ amqp_tls_version_t max);
+
+/**
+ * Sets whether rabbitmq-c will initialize OpenSSL.
+ *
+ * OpenSSL requires a one-time initialization across a whole program, this sets
+ * whether or not rabbitmq-c will initialize the SSL library when the first call
+ * to amqp_ssl_socket_new() is made. You should call this function with
+ * do_init = 0 if the underlying SSL library is initialized somewhere else
+ * the program.
+ *
+ * Failing to initialize or double initialization of the SSL library will
+ * result in undefined behavior
+ *
+ * By default rabbitmq-c will initialize the underlying SSL library.
+ *
+ * NOTE: calling this function after the first socket has been opened with
+ * amqp_open_socket() will not have any effect.
+ *
+ * \param [in] do_initialize If 0 rabbitmq-c will not initialize the SSL
+ * library, otherwise rabbitmq-c will initialize the
+ * SSL library
+ *
+ * \since v0.4.0
+ */
+AMQP_PUBLIC_FUNCTION
+void AMQP_CALL amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize);
+
+/**
+ * Initialize the underlying SSL/TLS library.
+ *
+ * The OpenSSL library requires a one-time initialization across the whole
+ * program.
+ *
+ * This function unconditionally initializes OpenSSL so that rabbitmq-c may
+ * use it.
+ *
+ * This function is thread-safe, and may be called more than once.
+ *
+ * \return AMQP_STATUS_OK on success.
+ *
+ * \since v0.9.0
+ */
+AMQP_PUBLIC_FUNCTION
+int AMQP_CALL amqp_initialize_ssl_library(void);
+
+/**
+ * Uninitialize the underlying SSL/TLS library.
+ *
+ * \return AMQP_STATUS_OK on success.
+ *
+ * \since v0.9.0
+ */
+AMQP_PUBLIC_FUNCTION
+int AMQP_CALL amqp_uninitialize_ssl_library(void);
+
+AMQP_END_DECLS
+
+#endif /* AMQP_SSL_H */
diff --git a/ext/librabbitmq/librabbitmq/amqp_table.c b/ext/librabbitmq/librabbitmq/amqp_table.c
new file mode 100644
index 000000000..24b087cc5
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_table.c
@@ -0,0 +1,668 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "amqp_private.h"
+#include "amqp_table.h"
+#include
+#include
+#include
+#include
+#include
+
+#define INITIAL_ARRAY_SIZE 16
+#define INITIAL_TABLE_SIZE 16
+
+static int amqp_decode_field_value(amqp_bytes_t encoded, amqp_pool_t *pool,
+ amqp_field_value_t *entry, size_t *offset);
+
+static int amqp_encode_field_value(amqp_bytes_t encoded,
+ amqp_field_value_t *entry, size_t *offset);
+
+/*---------------------------------------------------------------------------*/
+
+static int amqp_decode_array(amqp_bytes_t encoded, amqp_pool_t *pool,
+ amqp_array_t *output, size_t *offset) {
+ uint32_t arraysize;
+ int num_entries = 0;
+ int allocated_entries = INITIAL_ARRAY_SIZE;
+ amqp_field_value_t *entries;
+ size_t limit;
+ int res;
+
+ if (!amqp_decode_32(encoded, offset, &arraysize)) {
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+
+ if (arraysize + *offset > encoded.len) {
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+
+ entries = malloc(allocated_entries * sizeof(amqp_field_value_t));
+ if (entries == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ limit = *offset + arraysize;
+ while (*offset < limit) {
+ if (num_entries >= allocated_entries) {
+ void *newentries;
+ allocated_entries = allocated_entries * 2;
+ newentries =
+ realloc(entries, allocated_entries * sizeof(amqp_field_value_t));
+ res = AMQP_STATUS_NO_MEMORY;
+ if (newentries == NULL) {
+ goto out;
+ }
+
+ entries = newentries;
+ }
+
+ res = amqp_decode_field_value(encoded, pool, &entries[num_entries], offset);
+ if (res < 0) {
+ goto out;
+ }
+
+ num_entries++;
+ }
+
+ output->num_entries = num_entries;
+ output->entries =
+ amqp_pool_alloc(pool, num_entries * sizeof(amqp_field_value_t));
+ /* NULL is legitimate if we requested a zero-length block. */
+ if (output->entries == NULL) {
+ if (num_entries == 0) {
+ res = AMQP_STATUS_OK;
+ } else {
+ res = AMQP_STATUS_NO_MEMORY;
+ }
+ goto out;
+ }
+
+ memcpy(output->entries, entries, num_entries * sizeof(amqp_field_value_t));
+ res = AMQP_STATUS_OK;
+
+out:
+ free(entries);
+ return res;
+}
+
+int amqp_decode_table(amqp_bytes_t encoded, amqp_pool_t *pool,
+ amqp_table_t *output, size_t *offset) {
+ uint32_t tablesize;
+ int num_entries = 0;
+ amqp_table_entry_t *entries;
+ int allocated_entries = INITIAL_TABLE_SIZE;
+ size_t limit;
+ int res;
+
+ if (!amqp_decode_32(encoded, offset, &tablesize)) {
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+
+ if (tablesize + *offset > encoded.len) {
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ }
+
+ entries = malloc(allocated_entries * sizeof(amqp_table_entry_t));
+ if (entries == NULL) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ limit = *offset + tablesize;
+ while (*offset < limit) {
+ uint8_t keylen;
+
+ res = AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_8(encoded, offset, &keylen)) {
+ goto out;
+ }
+
+ if (num_entries >= allocated_entries) {
+ void *newentries;
+ allocated_entries = allocated_entries * 2;
+ newentries =
+ realloc(entries, allocated_entries * sizeof(amqp_table_entry_t));
+ res = AMQP_STATUS_NO_MEMORY;
+ if (newentries == NULL) {
+ goto out;
+ }
+
+ entries = newentries;
+ }
+
+ res = AMQP_STATUS_BAD_AMQP_DATA;
+ if (!amqp_decode_bytes(encoded, offset, &entries[num_entries].key,
+ keylen)) {
+ goto out;
+ }
+
+ res = amqp_decode_field_value(encoded, pool, &entries[num_entries].value,
+ offset);
+ if (res < 0) {
+ goto out;
+ }
+
+ num_entries++;
+ }
+
+ output->num_entries = num_entries;
+ output->entries =
+ amqp_pool_alloc(pool, num_entries * sizeof(amqp_table_entry_t));
+ /* NULL is legitimate if we requested a zero-length block. */
+ if (output->entries == NULL) {
+ if (num_entries == 0) {
+ res = AMQP_STATUS_OK;
+ } else {
+ res = AMQP_STATUS_NO_MEMORY;
+ }
+ goto out;
+ }
+
+ memcpy(output->entries, entries, num_entries * sizeof(amqp_table_entry_t));
+ res = AMQP_STATUS_OK;
+
+out:
+ free(entries);
+ return res;
+}
+
+static int amqp_decode_field_value(amqp_bytes_t encoded, amqp_pool_t *pool,
+ amqp_field_value_t *entry, size_t *offset) {
+ int res = AMQP_STATUS_BAD_AMQP_DATA;
+
+ if (!amqp_decode_8(encoded, offset, &entry->kind)) {
+ goto out;
+ }
+
+#define TRIVIAL_FIELD_DECODER(bits) \
+ if (!amqp_decode_##bits(encoded, offset, &entry->value.u##bits)) goto out; \
+ break
+#define SIMPLE_FIELD_DECODER(bits, dest, how) \
+ { \
+ uint##bits##_t val; \
+ if (!amqp_decode_##bits(encoded, offset, &val)) goto out; \
+ entry->value.dest = how; \
+ } \
+ break
+
+ switch (entry->kind) {
+ case AMQP_FIELD_KIND_BOOLEAN:
+ SIMPLE_FIELD_DECODER(8, boolean, val ? 1 : 0);
+
+ case AMQP_FIELD_KIND_I8:
+ SIMPLE_FIELD_DECODER(8, i8, (int8_t)val);
+ case AMQP_FIELD_KIND_U8:
+ TRIVIAL_FIELD_DECODER(8);
+
+ case AMQP_FIELD_KIND_I16:
+ SIMPLE_FIELD_DECODER(16, i16, (int16_t)val);
+ case AMQP_FIELD_KIND_U16:
+ TRIVIAL_FIELD_DECODER(16);
+
+ case AMQP_FIELD_KIND_I32:
+ SIMPLE_FIELD_DECODER(32, i32, (int32_t)val);
+ case AMQP_FIELD_KIND_U32:
+ TRIVIAL_FIELD_DECODER(32);
+
+ case AMQP_FIELD_KIND_I64:
+ SIMPLE_FIELD_DECODER(64, i64, (int64_t)val);
+ case AMQP_FIELD_KIND_U64:
+ TRIVIAL_FIELD_DECODER(64);
+
+ case AMQP_FIELD_KIND_F32:
+ TRIVIAL_FIELD_DECODER(32);
+ /* and by punning, f32 magically gets the right value...! */
+
+ case AMQP_FIELD_KIND_F64:
+ TRIVIAL_FIELD_DECODER(64);
+ /* and by punning, f64 magically gets the right value...! */
+
+ case AMQP_FIELD_KIND_DECIMAL:
+ if (!amqp_decode_8(encoded, offset, &entry->value.decimal.decimals) ||
+ !amqp_decode_32(encoded, offset, &entry->value.decimal.value)) {
+ goto out;
+ }
+ break;
+
+ case AMQP_FIELD_KIND_UTF8:
+ /* AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the
+ same implementation, but different interpretations. */
+ /* fall through */
+ case AMQP_FIELD_KIND_BYTES: {
+ uint32_t len;
+ if (!amqp_decode_32(encoded, offset, &len) ||
+ !amqp_decode_bytes(encoded, offset, &entry->value.bytes, len)) {
+ goto out;
+ }
+ break;
+ }
+
+ case AMQP_FIELD_KIND_ARRAY:
+ res = amqp_decode_array(encoded, pool, &(entry->value.array), offset);
+ goto out;
+
+ case AMQP_FIELD_KIND_TIMESTAMP:
+ TRIVIAL_FIELD_DECODER(64);
+
+ case AMQP_FIELD_KIND_TABLE:
+ res = amqp_decode_table(encoded, pool, &(entry->value.table), offset);
+ goto out;
+
+ case AMQP_FIELD_KIND_VOID:
+ break;
+
+ default:
+ goto out;
+ }
+
+ res = AMQP_STATUS_OK;
+
+out:
+ return res;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static int amqp_encode_array(amqp_bytes_t encoded, amqp_array_t *input,
+ size_t *offset) {
+ size_t start = *offset;
+ int i, res;
+
+ *offset += 4; /* size of the array gets filled in later on */
+
+ for (i = 0; i < input->num_entries; i++) {
+ res = amqp_encode_field_value(encoded, &input->entries[i], offset);
+ if (res < 0) {
+ goto out;
+ }
+ }
+
+ if (!amqp_encode_32(encoded, &start, (uint32_t)(*offset - start - 4))) {
+ res = AMQP_STATUS_TABLE_TOO_BIG;
+ goto out;
+ }
+
+ res = AMQP_STATUS_OK;
+
+out:
+ return res;
+}
+
+int amqp_encode_table(amqp_bytes_t encoded, amqp_table_t *input,
+ size_t *offset) {
+ size_t start = *offset;
+ int i, res;
+
+ *offset += 4; /* size of the table gets filled in later on */
+
+ for (i = 0; i < input->num_entries; i++) {
+ if (!amqp_encode_8(encoded, offset, (uint8_t)input->entries[i].key.len)) {
+ res = AMQP_STATUS_TABLE_TOO_BIG;
+ goto out;
+ }
+
+ if (!amqp_encode_bytes(encoded, offset, input->entries[i].key)) {
+ res = AMQP_STATUS_TABLE_TOO_BIG;
+ goto out;
+ }
+
+ res = amqp_encode_field_value(encoded, &input->entries[i].value, offset);
+ if (res < 0) {
+ goto out;
+ }
+ }
+
+ if (!amqp_encode_32(encoded, &start, (uint32_t)(*offset - start - 4))) {
+ res = AMQP_STATUS_TABLE_TOO_BIG;
+ goto out;
+ }
+
+ res = AMQP_STATUS_OK;
+
+out:
+ return res;
+}
+
+static int amqp_encode_field_value(amqp_bytes_t encoded,
+ amqp_field_value_t *entry, size_t *offset) {
+ int res = AMQP_STATUS_BAD_AMQP_DATA;
+
+ if (!amqp_encode_8(encoded, offset, entry->kind)) {
+ goto out;
+ }
+
+#define FIELD_ENCODER(bits, val) \
+ if (!amqp_encode_##bits(encoded, offset, val)) { \
+ res = AMQP_STATUS_TABLE_TOO_BIG; \
+ goto out; \
+ } \
+ break
+
+ switch (entry->kind) {
+ case AMQP_FIELD_KIND_BOOLEAN:
+ FIELD_ENCODER(8, entry->value.boolean ? 1 : 0);
+
+ case AMQP_FIELD_KIND_I8:
+ FIELD_ENCODER(8, entry->value.i8);
+ case AMQP_FIELD_KIND_U8:
+ FIELD_ENCODER(8, entry->value.u8);
+
+ case AMQP_FIELD_KIND_I16:
+ FIELD_ENCODER(16, entry->value.i16);
+ case AMQP_FIELD_KIND_U16:
+ FIELD_ENCODER(16, entry->value.u16);
+
+ case AMQP_FIELD_KIND_I32:
+ FIELD_ENCODER(32, entry->value.i32);
+ case AMQP_FIELD_KIND_U32:
+ FIELD_ENCODER(32, entry->value.u32);
+
+ case AMQP_FIELD_KIND_I64:
+ FIELD_ENCODER(64, entry->value.i64);
+ case AMQP_FIELD_KIND_U64:
+ FIELD_ENCODER(64, entry->value.u64);
+
+ case AMQP_FIELD_KIND_F32:
+ /* by punning, u32 magically gets the right value...! */
+ FIELD_ENCODER(32, entry->value.u32);
+
+ case AMQP_FIELD_KIND_F64:
+ /* by punning, u64 magically gets the right value...! */
+ FIELD_ENCODER(64, entry->value.u64);
+
+ case AMQP_FIELD_KIND_DECIMAL:
+ if (!amqp_encode_8(encoded, offset, entry->value.decimal.decimals) ||
+ !amqp_encode_32(encoded, offset, entry->value.decimal.value)) {
+ res = AMQP_STATUS_TABLE_TOO_BIG;
+ goto out;
+ }
+ break;
+
+ case AMQP_FIELD_KIND_UTF8:
+ /* AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the
+ same implementation, but different interpretations. */
+ /* fall through */
+ case AMQP_FIELD_KIND_BYTES:
+ if (!amqp_encode_32(encoded, offset, (uint32_t)entry->value.bytes.len) ||
+ !amqp_encode_bytes(encoded, offset, entry->value.bytes)) {
+ res = AMQP_STATUS_TABLE_TOO_BIG;
+ goto out;
+ }
+ break;
+
+ case AMQP_FIELD_KIND_ARRAY:
+ res = amqp_encode_array(encoded, &entry->value.array, offset);
+ goto out;
+
+ case AMQP_FIELD_KIND_TIMESTAMP:
+ FIELD_ENCODER(64, entry->value.u64);
+
+ case AMQP_FIELD_KIND_TABLE:
+ res = amqp_encode_table(encoded, &entry->value.table, offset);
+ goto out;
+
+ case AMQP_FIELD_KIND_VOID:
+ break;
+
+ default:
+ res = AMQP_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ res = AMQP_STATUS_OK;
+
+out:
+ return res;
+}
+
+/*---------------------------------------------------------------------------*/
+
+int amqp_table_entry_cmp(void const *entry1, void const *entry2) {
+ amqp_table_entry_t const *p1 = (amqp_table_entry_t const *)entry1;
+ amqp_table_entry_t const *p2 = (amqp_table_entry_t const *)entry2;
+
+ int d;
+ size_t minlen;
+
+ minlen = p1->key.len;
+ if (p2->key.len < minlen) {
+ minlen = p2->key.len;
+ }
+
+ d = memcmp(p1->key.bytes, p2->key.bytes, minlen);
+ if (d != 0) {
+ return d;
+ }
+
+ return (int)p1->key.len - (int)p2->key.len;
+}
+
+static int amqp_field_value_clone(const amqp_field_value_t *original,
+ amqp_field_value_t *clone,
+ amqp_pool_t *pool) {
+ int i;
+ int res;
+ clone->kind = original->kind;
+
+ switch (clone->kind) {
+ case AMQP_FIELD_KIND_BOOLEAN:
+ clone->value.boolean = original->value.boolean;
+ break;
+
+ case AMQP_FIELD_KIND_I8:
+ clone->value.i8 = original->value.i8;
+ break;
+
+ case AMQP_FIELD_KIND_U8:
+ clone->value.u8 = original->value.u8;
+ break;
+
+ case AMQP_FIELD_KIND_I16:
+ clone->value.i16 = original->value.i16;
+ break;
+
+ case AMQP_FIELD_KIND_U16:
+ clone->value.u16 = original->value.u16;
+ break;
+
+ case AMQP_FIELD_KIND_I32:
+ clone->value.i32 = original->value.i32;
+ break;
+
+ case AMQP_FIELD_KIND_U32:
+ clone->value.u32 = original->value.u32;
+ break;
+
+ case AMQP_FIELD_KIND_I64:
+ clone->value.i64 = original->value.i64;
+ break;
+
+ case AMQP_FIELD_KIND_U64:
+ case AMQP_FIELD_KIND_TIMESTAMP:
+ clone->value.u64 = original->value.u64;
+ break;
+
+ case AMQP_FIELD_KIND_F32:
+ clone->value.f32 = original->value.f32;
+ break;
+
+ case AMQP_FIELD_KIND_F64:
+ clone->value.f64 = original->value.f64;
+ break;
+
+ case AMQP_FIELD_KIND_DECIMAL:
+ clone->value.decimal = original->value.decimal;
+ break;
+
+ case AMQP_FIELD_KIND_UTF8:
+ case AMQP_FIELD_KIND_BYTES:
+ if (0 == original->value.bytes.len) {
+ clone->value.bytes = amqp_empty_bytes;
+ } else {
+ amqp_pool_alloc_bytes(pool, original->value.bytes.len,
+ &clone->value.bytes);
+ if (NULL == clone->value.bytes.bytes) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+ memcpy(clone->value.bytes.bytes, original->value.bytes.bytes,
+ clone->value.bytes.len);
+ }
+ break;
+
+ case AMQP_FIELD_KIND_ARRAY:
+ if (0 == original->value.array.entries) {
+ clone->value.array = amqp_empty_array;
+ } else {
+ clone->value.array.num_entries = original->value.array.num_entries;
+ clone->value.array.entries = amqp_pool_alloc(
+ pool, clone->value.array.num_entries * sizeof(amqp_field_value_t));
+ if (NULL == clone->value.array.entries) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < clone->value.array.num_entries; ++i) {
+ res = amqp_field_value_clone(&original->value.array.entries[i],
+ &clone->value.array.entries[i], pool);
+ if (AMQP_STATUS_OK != res) {
+ return res;
+ }
+ }
+ }
+ break;
+
+ case AMQP_FIELD_KIND_TABLE:
+ return amqp_table_clone(&original->value.table, &clone->value.table,
+ pool);
+
+ case AMQP_FIELD_KIND_VOID:
+ break;
+
+ default:
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+
+ return AMQP_STATUS_OK;
+}
+
+static int amqp_table_entry_clone(const amqp_table_entry_t *original,
+ amqp_table_entry_t *clone,
+ amqp_pool_t *pool) {
+ if (0 == original->key.len) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+
+ amqp_pool_alloc_bytes(pool, original->key.len, &clone->key);
+ if (NULL == clone->key.bytes) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ memcpy(clone->key.bytes, original->key.bytes, clone->key.len);
+
+ return amqp_field_value_clone(&original->value, &clone->value, pool);
+}
+
+int amqp_table_clone(const amqp_table_t *original, amqp_table_t *clone,
+ amqp_pool_t *pool) {
+ int i;
+ int res;
+ clone->num_entries = original->num_entries;
+ if (0 == clone->num_entries) {
+ *clone = amqp_empty_table;
+ return AMQP_STATUS_OK;
+ }
+
+ clone->entries =
+ amqp_pool_alloc(pool, clone->num_entries * sizeof(amqp_table_entry_t));
+
+ if (NULL == clone->entries) {
+ return AMQP_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < clone->num_entries; ++i) {
+ res =
+ amqp_table_entry_clone(&original->entries[i], &clone->entries[i], pool);
+ if (AMQP_STATUS_OK != res) {
+ goto error_out1;
+ }
+ }
+
+ return AMQP_STATUS_OK;
+
+error_out1:
+ return res;
+}
+
+amqp_table_entry_t amqp_table_construct_utf8_entry(const char *key,
+ const char *value) {
+ amqp_table_entry_t ret;
+ ret.key = amqp_cstring_bytes(key);
+ ret.value.kind = AMQP_FIELD_KIND_UTF8;
+ ret.value.value.bytes = amqp_cstring_bytes(value);
+ return ret;
+}
+
+amqp_table_entry_t amqp_table_construct_table_entry(const char *key,
+ const amqp_table_t *value) {
+ amqp_table_entry_t ret;
+ ret.key = amqp_cstring_bytes(key);
+ ret.value.kind = AMQP_FIELD_KIND_TABLE;
+ ret.value.value.table = *value;
+ return ret;
+}
+
+amqp_table_entry_t amqp_table_construct_bool_entry(const char *key,
+ const int value) {
+ amqp_table_entry_t ret;
+ ret.key = amqp_cstring_bytes(key);
+ ret.value.kind = AMQP_FIELD_KIND_BOOLEAN;
+ ret.value.value.boolean = value;
+ return ret;
+}
+
+amqp_table_entry_t *amqp_table_get_entry_by_key(const amqp_table_t *table,
+ const amqp_bytes_t key) {
+ int i;
+ assert(table != NULL);
+ for (i = 0; i < table->num_entries; ++i) {
+ if (amqp_bytes_equal(table->entries[i].key, key)) {
+ return &table->entries[i];
+ }
+ }
+ return NULL;
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_table.h b/ext/librabbitmq/librabbitmq/amqp_table.h
new file mode 100644
index 000000000..7b009a999
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_table.h
@@ -0,0 +1,81 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2014 Alan Antonuk.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+#ifndef AMQP_TABLE_H
+#define AMQP_TABLE_H
+
+#include "amqp.h"
+#include "amqp_private.h"
+
+/**
+ * Initializes a table entry with utf-8 string type value.
+ *
+ * \param [in] key the table entry key. The string must remain valid for the
+ * life of the resulting amqp_table_entry_t.
+ * \param [in] value the string value. The string must remain valid for the life
+ * of the resulting amqp_table_entry_t.
+ * \returns An initialized table entry.
+ */
+amqp_table_entry_t amqp_table_construct_utf8_entry(const char *key,
+ const char *value);
+
+/**
+ * Initializes a table entry with table type value.
+ *
+ * \param [in] key the table entry key. The string must remain value for the
+ * life of the resulting amqp_table_entry_t.
+ * \param [in] value the amqp_table_t value. The table must remain valid for the
+ * life of the resulting amqp_table_entry_t.
+ * \returns An initialized table entry.
+ */
+amqp_table_entry_t amqp_table_construct_table_entry(const char *key,
+ const amqp_table_t *value);
+
+/**
+ * Initializes a table entry with boolean type value.
+ *
+ * \param [in] key the table entry key. The string must remain value for the
+ * life of the resulting amqp_table_entry_t.
+ * \param [in] value the boolean value. 0 means false, any other value is true.
+ * \returns An initialized table entry.
+ */
+amqp_table_entry_t amqp_table_construct_bool_entry(const char *key,
+ const int value);
+
+/**
+ * Searches a table for an entry with a matching key.
+ *
+ * \param [in] table the table to search.
+ * \param [in] key the string to search with.
+ * \returns a pointer to the table entry in the table if a matching key can be
+ * found, NULL otherwise.
+ */
+amqp_table_entry_t *amqp_table_get_entry_by_key(const amqp_table_t *table,
+ const amqp_bytes_t key);
+
+#endif /* AMQP_TABLE_H */
diff --git a/ext/librabbitmq/librabbitmq/amqp_tcp_socket.c b/ext/librabbitmq/librabbitmq/amqp_tcp_socket.c
new file mode 100644
index 000000000..12e02cd26
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_tcp_socket.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2012-2013 Michael Steinert
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "amqp_private.h"
+#include "amqp_tcp_socket.h"
+
+#include
+#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+#else
+#include
+#include
+#include
+#endif
+#include
+#include
+
+struct amqp_tcp_socket_t {
+ const struct amqp_socket_class_t *klass;
+ int sockfd;
+ int internal_error;
+ int state;
+};
+
+static ssize_t amqp_tcp_socket_send(void *base, const void *buf, size_t len,
+ int flags) {
+ struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
+ ssize_t res;
+ int flagz = 0;
+
+ if (-1 == self->sockfd) {
+ return AMQP_STATUS_SOCKET_CLOSED;
+ }
+
+#ifdef MSG_NOSIGNAL
+ flagz |= MSG_NOSIGNAL;
+#endif
+
+#if defined(MSG_MORE)
+ if (flags & AMQP_SF_MORE) {
+ flagz |= MSG_MORE;
+ }
+/* Cygwin defines TCP_NOPUSH, but trying to use it will return not
+ * implemented. Disable it here. */
+#elif defined(TCP_NOPUSH) && !defined(__CYGWIN__)
+ if (flags & AMQP_SF_MORE && !(self->state & AMQP_SF_MORE)) {
+ int one = 1;
+ res = setsockopt(self->sockfd, IPPROTO_TCP, TCP_NOPUSH, &one, sizeof(one));
+ if (0 != res) {
+ self->internal_error = res;
+ return AMQP_STATUS_SOCKET_ERROR;
+ }
+ self->state |= AMQP_SF_MORE;
+ } else if (!(flags & AMQP_SF_MORE) && self->state & AMQP_SF_MORE) {
+ int zero = 0;
+ res =
+ setsockopt(self->sockfd, IPPROTO_TCP, TCP_NOPUSH, &zero, sizeof(&zero));
+ if (0 != res) {
+ self->internal_error = res;
+ res = AMQP_STATUS_SOCKET_ERROR;
+ } else {
+ self->state &= ~AMQP_SF_MORE;
+ }
+ }
+#endif
+
+start:
+#ifdef _WIN32
+ res = send(self->sockfd, buf, (int)len, flagz);
+#else
+ res = send(self->sockfd, buf, len, flagz);
+#endif
+
+ if (res < 0) {
+ self->internal_error = amqp_os_socket_error();
+ switch (self->internal_error) {
+ case EINTR:
+ goto start;
+#ifdef _WIN32
+ case WSAEWOULDBLOCK:
+#else
+ case EWOULDBLOCK:
+#endif
+#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+ res = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
+ break;
+ default:
+ res = AMQP_STATUS_SOCKET_ERROR;
+ }
+ } else {
+ self->internal_error = 0;
+ }
+
+ return res;
+}
+
+static ssize_t amqp_tcp_socket_recv(void *base, void *buf, size_t len,
+ int flags) {
+ struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
+ ssize_t ret;
+ if (-1 == self->sockfd) {
+ return AMQP_STATUS_SOCKET_CLOSED;
+ }
+
+start:
+#ifdef _WIN32
+ ret = recv(self->sockfd, buf, (int)len, flags);
+#else
+ ret = recv(self->sockfd, buf, len, flags);
+#endif
+
+ if (0 > ret) {
+ self->internal_error = amqp_os_socket_error();
+ switch (self->internal_error) {
+ case EINTR:
+ goto start;
+#ifdef _WIN32
+ case WSAEWOULDBLOCK:
+#else
+ case EWOULDBLOCK:
+#endif
+#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+ ret = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
+ break;
+ default:
+ ret = AMQP_STATUS_SOCKET_ERROR;
+ }
+ } else if (0 == ret) {
+ ret = AMQP_STATUS_CONNECTION_CLOSED;
+ }
+
+ return ret;
+}
+
+static int amqp_tcp_socket_open(void *base, const char *host, int port,
+ struct timeval *timeout) {
+ struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
+ if (-1 != self->sockfd) {
+ return AMQP_STATUS_SOCKET_INUSE;
+ }
+ self->sockfd = amqp_open_socket_noblock(host, port, timeout);
+ if (0 > self->sockfd) {
+ int err = self->sockfd;
+ self->sockfd = -1;
+ return err;
+ }
+ return AMQP_STATUS_OK;
+}
+
+static int amqp_tcp_socket_close(void *base,
+ AMQP_UNUSED amqp_socket_close_enum force) {
+ struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
+ if (-1 == self->sockfd) {
+ return AMQP_STATUS_SOCKET_CLOSED;
+ }
+
+ if (amqp_os_socket_close(self->sockfd)) {
+ return AMQP_STATUS_SOCKET_ERROR;
+ }
+ self->sockfd = -1;
+
+ return AMQP_STATUS_OK;
+}
+
+static int amqp_tcp_socket_get_sockfd(void *base) {
+ struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
+ return self->sockfd;
+}
+
+static void amqp_tcp_socket_delete(void *base) {
+ struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
+
+ if (self) {
+ amqp_tcp_socket_close(self, AMQP_SC_NONE);
+ free(self);
+ }
+}
+
+static const struct amqp_socket_class_t amqp_tcp_socket_class = {
+ amqp_tcp_socket_send, /* send */
+ amqp_tcp_socket_recv, /* recv */
+ amqp_tcp_socket_open, /* open */
+ amqp_tcp_socket_close, /* close */
+ amqp_tcp_socket_get_sockfd, /* get_sockfd */
+ amqp_tcp_socket_delete /* delete */
+};
+
+amqp_socket_t *amqp_tcp_socket_new(amqp_connection_state_t state) {
+ struct amqp_tcp_socket_t *self = calloc(1, sizeof(*self));
+ if (!self) {
+ return NULL;
+ }
+ self->klass = &amqp_tcp_socket_class;
+ self->sockfd = -1;
+
+ amqp_set_socket(state, (amqp_socket_t *)self);
+
+ return (amqp_socket_t *)self;
+}
+
+void amqp_tcp_socket_set_sockfd(amqp_socket_t *base, int sockfd) {
+ struct amqp_tcp_socket_t *self;
+ if (base->klass != &amqp_tcp_socket_class) {
+ amqp_abort("<%p> is not of type amqp_tcp_socket_t", base);
+ }
+ self = (struct amqp_tcp_socket_t *)base;
+ self->sockfd = sockfd;
+}
diff --git a/ext/librabbitmq/centos_x64/include/amqp_tcp_socket.h b/ext/librabbitmq/librabbitmq/amqp_tcp_socket.h
similarity index 100%
rename from ext/librabbitmq/centos_x64/include/amqp_tcp_socket.h
rename to ext/librabbitmq/librabbitmq/amqp_tcp_socket.h
diff --git a/ext/librabbitmq/librabbitmq/amqp_time.c b/ext/librabbitmq/librabbitmq/amqp_time.c
new file mode 100644
index 000000000..7b0a42d06
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_time.c
@@ -0,0 +1,265 @@
+/*
+ * Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include "amqp_time.h"
+#include "amqp.h"
+#include
+#include
+#include
+
+#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || \
+ defined(__MINGW32__) || defined(__MINGW64__))
+#define AMQP_WIN_TIMER_API
+#elif (defined(machintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
+#define AMQP_MAC_TIMER_API
+#else
+#define AMQP_POSIX_TIMER_API
+#endif
+
+#ifdef AMQP_WIN_TIMER_API
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+
+uint64_t amqp_get_monotonic_timestamp(void) {
+ static double NS_PER_COUNT = 0;
+ LARGE_INTEGER perf_count;
+
+ if (0 == NS_PER_COUNT) {
+ LARGE_INTEGER perf_frequency;
+ if (!QueryPerformanceFrequency(&perf_frequency)) {
+ return 0;
+ }
+ NS_PER_COUNT = (double)AMQP_NS_PER_S / perf_frequency.QuadPart;
+ }
+
+ if (!QueryPerformanceCounter(&perf_count)) {
+ return 0;
+ }
+
+ return (uint64_t)(perf_count.QuadPart * NS_PER_COUNT);
+}
+#endif /* AMQP_WIN_TIMER_API */
+
+#ifdef AMQP_MAC_TIMER_API
+#include
+
+uint64_t amqp_get_monotonic_timestamp(void) {
+ static mach_timebase_info_data_t s_timebase = {0, 0};
+ uint64_t timestamp;
+
+ timestamp = mach_absolute_time();
+
+ if (s_timebase.denom == 0) {
+ mach_timebase_info(&s_timebase);
+ if (0 == s_timebase.denom) {
+ return 0;
+ }
+ }
+
+ timestamp *= (uint64_t)s_timebase.numer;
+ timestamp /= (uint64_t)s_timebase.denom;
+
+ return timestamp;
+}
+#endif /* AMQP_MAC_TIMER_API */
+
+#ifdef AMQP_POSIX_TIMER_API
+#include
+
+uint64_t amqp_get_monotonic_timestamp(void) {
+#ifdef __hpux
+ return (uint64_t)gethrtime();
+#else
+ struct timespec tp;
+ if (-1 == clock_gettime(CLOCK_MONOTONIC, &tp)) {
+ return 0;
+ }
+
+ return ((uint64_t)tp.tv_sec * AMQP_NS_PER_S + (uint64_t)tp.tv_nsec);
+#endif
+}
+#endif /* AMQP_POSIX_TIMER_API */
+
+int amqp_time_from_now(amqp_time_t *time, struct timeval *timeout) {
+ uint64_t now_ns;
+ uint64_t delta_ns;
+
+ assert(NULL != time);
+
+ if (NULL == timeout) {
+ *time = amqp_time_infinite();
+ return AMQP_STATUS_OK;
+ }
+ if (0 == timeout->tv_sec && 0 == timeout->tv_usec) {
+ *time = amqp_time_immediate();
+ return AMQP_STATUS_OK;
+ }
+
+ if (timeout->tv_sec < 0 || timeout->tv_usec < 0) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+
+ delta_ns = (uint64_t)timeout->tv_sec * AMQP_NS_PER_S +
+ (uint64_t)timeout->tv_usec * AMQP_NS_PER_US;
+
+ now_ns = amqp_get_monotonic_timestamp();
+ if (0 == now_ns) {
+ return AMQP_STATUS_TIMER_FAILURE;
+ }
+
+ time->time_point_ns = now_ns + delta_ns;
+ if (now_ns > time->time_point_ns || delta_ns > time->time_point_ns) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+
+ return AMQP_STATUS_OK;
+}
+
+int amqp_time_s_from_now(amqp_time_t *time, int seconds) {
+ uint64_t now_ns;
+ uint64_t delta_ns;
+ assert(NULL != time);
+
+ if (0 >= seconds) {
+ *time = amqp_time_infinite();
+ return AMQP_STATUS_OK;
+ }
+
+ now_ns = amqp_get_monotonic_timestamp();
+ if (0 == now_ns) {
+ return AMQP_STATUS_TIMER_FAILURE;
+ }
+
+ delta_ns = (uint64_t)seconds * AMQP_NS_PER_S;
+ time->time_point_ns = now_ns + delta_ns;
+ if (now_ns > time->time_point_ns || delta_ns > time->time_point_ns) {
+ return AMQP_STATUS_INVALID_PARAMETER;
+ }
+
+ return AMQP_STATUS_OK;
+}
+
+amqp_time_t amqp_time_immediate(void) {
+ amqp_time_t time;
+ time.time_point_ns = 0;
+ return time;
+}
+
+amqp_time_t amqp_time_infinite(void) {
+ amqp_time_t time;
+ time.time_point_ns = UINT64_MAX;
+ return time;
+}
+
+int amqp_time_ms_until(amqp_time_t time) {
+ uint64_t now_ns;
+ uint64_t delta_ns;
+ int left_ms;
+
+ if (UINT64_MAX == time.time_point_ns) {
+ return -1;
+ }
+ if (0 == time.time_point_ns) {
+ return 0;
+ }
+
+ now_ns = amqp_get_monotonic_timestamp();
+ if (0 == now_ns) {
+ return AMQP_STATUS_TIMER_FAILURE;
+ }
+
+ if (now_ns >= time.time_point_ns) {
+ return 0;
+ }
+
+ delta_ns = time.time_point_ns - now_ns;
+ left_ms = (int)(delta_ns / AMQP_NS_PER_MS);
+
+ return left_ms;
+}
+
+int amqp_time_tv_until(amqp_time_t time, struct timeval *in,
+ struct timeval **out) {
+ uint64_t now_ns;
+ uint64_t delta_ns;
+
+ assert(in != NULL);
+ if (UINT64_MAX == time.time_point_ns) {
+ *out = NULL;
+ return AMQP_STATUS_OK;
+ }
+ if (0 == time.time_point_ns) {
+ in->tv_sec = 0;
+ in->tv_usec = 0;
+ *out = in;
+ return AMQP_STATUS_OK;
+ }
+
+ now_ns = amqp_get_monotonic_timestamp();
+ if (0 == now_ns) {
+ return AMQP_STATUS_TIMER_FAILURE;
+ }
+
+ if (now_ns >= time.time_point_ns) {
+ in->tv_sec = 0;
+ in->tv_usec = 0;
+ *out = in;
+ return AMQP_STATUS_OK;
+ }
+
+ delta_ns = time.time_point_ns - now_ns;
+ in->tv_sec = (int)(delta_ns / AMQP_NS_PER_S);
+ in->tv_usec = (int)((delta_ns % AMQP_NS_PER_S) / AMQP_NS_PER_US);
+ *out = in;
+
+ return AMQP_STATUS_OK;
+}
+
+int amqp_time_has_past(amqp_time_t time) {
+ uint64_t now_ns;
+ if (UINT64_MAX == time.time_point_ns) {
+ return AMQP_STATUS_OK;
+ }
+
+ now_ns = amqp_get_monotonic_timestamp();
+ if (0 == now_ns) {
+ return AMQP_STATUS_TIMER_FAILURE;
+ }
+
+ if (now_ns > time.time_point_ns) {
+ return AMQP_STATUS_TIMEOUT;
+ }
+ return AMQP_STATUS_OK;
+}
+
+amqp_time_t amqp_time_first(amqp_time_t l, amqp_time_t r) {
+ if (l.time_point_ns < r.time_point_ns) {
+ return l;
+ }
+ return r;
+}
+
+int amqp_time_equal(amqp_time_t l, amqp_time_t r) {
+ return l.time_point_ns == r.time_point_ns;
+}
diff --git a/ext/librabbitmq/librabbitmq/amqp_time.h b/ext/librabbitmq/librabbitmq/amqp_time.h
new file mode 100644
index 000000000..194bf6715
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_time.h
@@ -0,0 +1,130 @@
+/*
+ * Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef AMQP_TIMER_H
+#define AMQP_TIMER_H
+
+#include
+
+#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
+#ifndef WINVER
+#define WINVER 0x0502
+#endif
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+#else
+#include
+#endif
+
+#define AMQP_MS_PER_S 1000
+#define AMQP_US_PER_MS 1000
+#define AMQP_NS_PER_S 1000000000
+#define AMQP_NS_PER_MS 1000000
+#define AMQP_NS_PER_US 1000
+
+/* This represents a point in time in reference to a monotonic clock.
+ *
+ * The internal representation is ns, relative to the monotonic clock.
+ *
+ * There are two 'special' values:
+ * - 0: means 'this instant', its meant for polls with a 0-timeout, or
+ * non-blocking option
+ * - UINT64_MAX: means 'at infinity', its mean for polls with an infinite
+ * timeout
+ */
+typedef struct amqp_time_t_ { uint64_t time_point_ns; } amqp_time_t;
+
+/* Gets a monotonic timestamp. This will return 0 if the underlying call to the
+ * system fails.
+ */
+uint64_t amqp_get_monotonic_timestamp(void);
+
+/* Get a amqp_time_t that is timeout from now.
+ * If timeout is NULL, an amqp_time_infinite() is created.
+ * If timeout = {0, 0}, an amqp_time_immediate() is created.
+ *
+ * Returns AMQP_STATUS_OK on success.
+ * AMQP_STATUS_INVALID_PARAMETER if timeout is invalid
+ * AMQP_STATUS_TIMER_FAILURE if the underlying call to get the current timestamp
+ * fails.
+ */
+int amqp_time_from_now(amqp_time_t *time, struct timeval *timeout);
+
+/* Get a amqp_time_t that is seconds from now.
+ * If seconds <= 0, then amqp_time_infinite() is created.
+ *
+ * Returns AMQP_STATUS_OK on success.
+ * AMQP_STATUS_TIMER_FAILURE if the underlying call to get the current timestamp
+ * fails.
+ */
+int amqp_time_s_from_now(amqp_time_t *time, int seconds);
+
+/* Create an immediate amqp_time_t */
+amqp_time_t amqp_time_immediate(void);
+
+/* Create an infinite amqp_time_t */
+amqp_time_t amqp_time_infinite(void);
+
+/* Gets the number of ms until the amqp_time_t, suitable for the timeout
+ * parameter in poll().
+ *
+ * -1 will be returned for amqp_time_infinite values.
+ * 0 will be returned for amqp_time_immediate values.
+ * AMQP_STATUS_TIMEOUT will be returned if time was in the past.
+ * AMQP_STATUS_TIMER_FAILURE will be returned if the underlying call to get the
+ * current timestamp fails.
+ */
+int amqp_time_ms_until(amqp_time_t time);
+
+/* Gets a timeval filled in with the time until amqp_time_t. Suitable for the
+ * parameter in select().
+ *
+ * The in parameter specifies a storage location for *out.
+ * If time is an inf timeout, then *out = NULL.
+ * If time is a 0-timeout or the timer has expired, then *out = {0, 0}
+ * Otherwise *out is set to the time left on the time.
+ *
+ * AMQP_STATUS_OK will be returned if successfully filled.
+ * AMQP_STATUS_TIMER_FAILURE is returned when the underlying call to get the
+ * current timestamp fails.
+ */
+int amqp_time_tv_until(amqp_time_t time, struct timeval *in,
+ struct timeval **out);
+
+/* Test whether current time is past the provided time.
+ *
+ * TODO: this isn't a great interface to use. Fix this.
+ *
+ * Return AMQP_STATUS_OK if time has not past
+ * Return AMQP_STATUS_TIMEOUT if time has past
+ * Return AMQP_STATUS_TIMER_FAILURE if the underlying call to get the current
+ * timestamp fails.
+ */
+int amqp_time_has_past(amqp_time_t time);
+
+/* Return the time value that happens first */
+amqp_time_t amqp_time_first(amqp_time_t l, amqp_time_t r);
+
+int amqp_time_equal(amqp_time_t l, amqp_time_t r);
+#endif /* AMQP_TIMER_H */
diff --git a/ext/librabbitmq/librabbitmq/amqp_url.c b/ext/librabbitmq/librabbitmq/amqp_url.c
new file mode 100644
index 000000000..b5304e545
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/amqp_url.c
@@ -0,0 +1,220 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "amqp_private.h"
+#include
+#include
+#include
+#include
+#include
+
+void amqp_default_connection_info(struct amqp_connection_info *ci) {
+ /* Apply defaults */
+ ci->user = "guest";
+ ci->password = "guest";
+ ci->host = "localhost";
+ ci->port = 5672;
+ ci->vhost = "/";
+ ci->ssl = 0;
+}
+
+/* Scan for the next delimiter, handling percent-encodings on the way. */
+static char find_delim(char **pp, int colon_and_at_sign_are_delims) {
+ char *from = *pp;
+ char *to = from;
+
+ for (;;) {
+ char ch = *from++;
+
+ switch (ch) {
+ case ':':
+ case '@':
+ if (!colon_and_at_sign_are_delims) {
+ *to++ = ch;
+ break;
+ }
+
+ /* fall through */
+ case 0:
+ case '/':
+ case '?':
+ case '#':
+ case '[':
+ case ']':
+ *to = 0;
+ *pp = from;
+ return ch;
+
+ case '%': {
+ unsigned int val;
+ int chars;
+ int res = sscanf(from, "%2x%n", &val, &chars);
+
+ if (res == EOF || res < 1 || chars != 2 || val > CHAR_MAX)
+ /* Return a surprising delimiter to
+ force an error. */
+ {
+ return '%';
+ }
+
+ *to++ = (char)val;
+ from += 2;
+ break;
+ }
+
+ default:
+ *to++ = ch;
+ break;
+ }
+ }
+}
+
+/* Parse an AMQP URL into its component parts. */
+int amqp_parse_url(char *url, struct amqp_connection_info *parsed) {
+ int res = AMQP_STATUS_BAD_URL;
+ char delim;
+ char *start;
+ char *host;
+ char *port = NULL;
+
+ amqp_default_connection_info(parsed);
+
+ /* check the prefix */
+ if (!strncmp(url, "amqp://", 7)) {
+ /* do nothing */
+ } else if (!strncmp(url, "amqps://", 8)) {
+ parsed->port = 5671;
+ parsed->ssl = 1;
+ } else {
+ goto out;
+ }
+
+ host = start = url += (parsed->ssl ? 8 : 7);
+ delim = find_delim(&url, 1);
+
+ if (delim == ':') {
+ /* The colon could be introducing the port or the
+ password part of the userinfo. We don't know yet,
+ so stash the preceding component. */
+ port = start = url;
+ delim = find_delim(&url, 1);
+ }
+
+ if (delim == '@') {
+ /* What might have been the host and port were in fact
+ the username and password */
+ parsed->user = host;
+ if (port) {
+ parsed->password = port;
+ }
+
+ port = NULL;
+ host = start = url;
+ delim = find_delim(&url, 1);
+ }
+
+ if (delim == '[') {
+ /* IPv6 address. The bracket should be the first
+ character in the host. */
+ if (host != start || *host != 0) {
+ goto out;
+ }
+
+ start = url;
+ delim = find_delim(&url, 0);
+
+ if (delim != ']') {
+ goto out;
+ }
+
+ parsed->host = start;
+ start = url;
+ delim = find_delim(&url, 1);
+
+ /* Closing bracket should be the last character in the
+ host. */
+ if (*start != 0) {
+ goto out;
+ }
+ } else {
+ /* If we haven't seen the host yet, this is it. */
+ if (*host != 0) {
+ parsed->host = host;
+ }
+ }
+
+ if (delim == ':') {
+ port = start = url;
+ delim = find_delim(&url, 1);
+ }
+
+ if (port) {
+ char *end;
+ long portnum = strtol(port, &end, 10);
+
+ if (port == end || *end != 0 || portnum < 0 || portnum > 65535) {
+ goto out;
+ }
+
+ parsed->port = portnum;
+ }
+
+ if (delim == '/') {
+ start = url;
+ delim = find_delim(&url, 1);
+
+ if (delim != 0) {
+ goto out;
+ }
+
+ parsed->vhost = start;
+ res = AMQP_STATUS_OK;
+ } else if (delim == 0) {
+ res = AMQP_STATUS_OK;
+ }
+
+/* Any other delimiter is bad, and we will return AMQP_STATUS_BAD_AMQP_URL. */
+
+out:
+ return res;
+}
diff --git a/ext/librabbitmq/librabbitmq/codegen.py b/ext/librabbitmq/librabbitmq/codegen.py
new file mode 100644
index 000000000..3ae24b634
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/codegen.py
@@ -0,0 +1,785 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MIT
+#
+# Portions created by Alan Antonuk are Copyright (c) 2012-2013
+# Alan Antonuk. All Rights Reserved.
+#
+# Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+# All Rights Reserved.
+#
+# Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+# VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ***** END LICENSE BLOCK *****
+
+from __future__ import nested_scopes
+from __future__ import division
+
+from amqp_codegen import *
+import string
+import re
+
+
+class Emitter(object):
+ """An object the trivially emits generated code lines.
+
+ This largely exists to be wrapped by more sophisticated emitter
+ classes.
+ """
+
+ def __init__(self, prefix):
+ self.prefix = prefix
+
+ def emit(self, line):
+ """Emit a line of generated code."""
+ print self.prefix + line
+
+
+class BitDecoder(object):
+ """An emitter object that keeps track of the state involved in
+ decoding the AMQP bit type."""
+
+ def __init__(self, emitter):
+ self.emitter = emitter
+ self.bit = 0
+
+ def emit(self, line):
+ self.bit = 0
+ self.emitter.emit(line)
+
+ def decode_bit(self, lvalue):
+ """Generate code to decode a value of the AMQP bit type into
+ the given lvalue."""
+ if self.bit == 0:
+ self.emitter.emit("if (!amqp_decode_8(encoded, &offset, &bit_buffer)) return AMQP_STATUS_BAD_AMQP_DATA;")
+
+ self.emitter.emit("%s = (bit_buffer & (1 << %d)) ? 1 : 0;"
+ % (lvalue, self.bit))
+ self.bit += 1
+ if self.bit == 8:
+ self.bit = 0
+
+
+class BitEncoder(object):
+ """An emitter object that keeps track of the state involved in
+ encoding the AMQP bit type."""
+
+ def __init__(self, emitter):
+ self.emitter = emitter
+ self.bit = 0
+
+ def flush(self):
+ """Flush the state associated with AMQP bit types."""
+ if self.bit:
+ self.emitter.emit("if (!amqp_encode_8(encoded, &offset, bit_buffer)) return AMQP_STATUS_BAD_AMQP_DATA;")
+ self.bit = 0
+
+ def emit(self, line):
+ self.flush()
+ self.emitter.emit(line)
+
+ def encode_bit(self, value):
+ """Generate code to encode a value of the AMQP bit type from
+ the given value."""
+ if self.bit == 0:
+ self.emitter.emit("bit_buffer = 0;")
+
+ self.emitter.emit("if (%s) bit_buffer |= (1 << %d);"
+ % (value, self.bit))
+ self.bit += 1
+ if self.bit == 8:
+ self.flush()
+
+
+class SimpleType(object):
+ """A AMQP type that corresponds to a simple scalar C value of a
+ certain width."""
+
+ def __init__(self, bits):
+ self.bits = bits
+ self.ctype = "uint%d_t" % (bits,)
+
+ def decode(self, emitter, lvalue):
+ emitter.emit("if (!amqp_decode_%d(encoded, &offset, &%s)) return AMQP_STATUS_BAD_AMQP_DATA;" % (self.bits, lvalue))
+
+ def encode(self, emitter, value):
+ emitter.emit("if (!amqp_encode_%d(encoded, &offset, %s)) return AMQP_STATUS_BAD_AMQP_DATA;" % (self.bits, value))
+
+ def literal(self, value):
+ return value
+
+class StrType(object):
+ """The AMQP shortstr or longstr types."""
+
+ def __init__(self, lenbits):
+ self.lenbits = lenbits
+ self.ctype = "amqp_bytes_t"
+
+ def decode(self, emitter, lvalue):
+ emitter.emit("{")
+ emitter.emit(" uint%d_t len;" % (self.lenbits,))
+ emitter.emit(" if (!amqp_decode_%d(encoded, &offset, &len)" % (self.lenbits,))
+ emitter.emit(" || !amqp_decode_bytes(encoded, &offset, &%s, len))" % (lvalue,))
+ emitter.emit(" return AMQP_STATUS_BAD_AMQP_DATA;")
+ emitter.emit("}")
+
+ def encode(self, emitter, value):
+ emitter.emit("if (UINT%d_MAX < %s.len" % (self.lenbits, value))
+ emitter.emit(" || !amqp_encode_%d(encoded, &offset, (uint%d_t)%s.len)" %
+ (self.lenbits, self.lenbits, value))
+ emitter.emit(" || !amqp_encode_bytes(encoded, &offset, %s))" % (value,))
+ emitter.emit(" return AMQP_STATUS_BAD_AMQP_DATA;")
+
+ def literal(self, value):
+ if value != '':
+ raise NotImplementedError()
+
+ return "amqp_empty_bytes"
+
+class BitType(object):
+ """The AMQP bit type."""
+
+ def __init__(self):
+ self.ctype = "amqp_boolean_t"
+
+ def decode(self, emitter, lvalue):
+ emitter.decode_bit(lvalue)
+
+ def encode(self, emitter, value):
+ emitter.encode_bit(value)
+
+ def literal(self, value):
+ return {True: 1, False: 0}[value]
+
+class TableType(object):
+ """The AMQP table type."""
+
+ def __init__(self):
+ self.ctype = "amqp_table_t"
+
+ def decode(self, emitter, lvalue):
+ emitter.emit("{")
+ emitter.emit(" int res = amqp_decode_table(encoded, pool, &(%s), &offset);" % (lvalue,))
+ emitter.emit(" if (res < 0) return res;")
+ emitter.emit("}")
+
+ def encode(self, emitter, value):
+ emitter.emit("{")
+ emitter.emit(" int res = amqp_encode_table(encoded, &(%s), &offset);" % (value,))
+ emitter.emit(" if (res < 0) return res;")
+ emitter.emit("}")
+
+ def literal(self, value):
+ raise NotImplementedError()
+
+types = {
+ 'octet': SimpleType(8),
+ 'short': SimpleType(16),
+ 'long': SimpleType(32),
+ 'longlong': SimpleType(64),
+ 'shortstr': StrType(8),
+ 'longstr': StrType(32),
+ 'bit': BitType(),
+ 'table': TableType(),
+ 'timestamp': SimpleType(64),
+}
+
+def typeFor(spec, f):
+ """Get a representation of the AMQP type of a field."""
+ return types[spec.resolveDomain(f.domain)]
+
+def c_ize(s):
+ s = s.replace('-', '_')
+ s = s.replace(' ', '_')
+ return s
+
+# When generating API functions corresponding to synchronous methods,
+# we need some information that isn't in the protocol def: Some
+# methods should not be exposed, indicated here by a False value.
+# Some methods should be exposed but certain fields should not be
+# exposed as parameters.
+apiMethodInfo = {
+ "amqp_connection_start": False, # application code should not use this
+ "amqp_connection_secure": False, # application code should not use this
+ "amqp_connection_tune": False, # application code should not use this
+ "amqp_connection_open": False, # application code should not use this
+ "amqp_connection_close": False, # needs special handling
+ "amqp_channel_open": ["out_of_band"],
+ "amqp_channel_close": False, # needs special handling
+ "amqp_access_request": False, # huh?
+ "amqp_basic_get": False, # get-ok has content
+}
+
+# When generating API functions corresponding to synchronous methods,
+# some fields should be suppressed everywhere. This dict names those
+# fields, and the fixed values to use for them.
+apiMethodsSuppressArgs = {"ticket": 0, "nowait": False}
+
+AmqpMethod.defName = lambda m: cConstantName(c_ize(m.klass.name) + '_' + c_ize(m.name) + "_method")
+AmqpMethod.fullName = lambda m: "amqp_%s_%s" % (c_ize(m.klass.name), c_ize(m.name))
+AmqpMethod.structName = lambda m: m.fullName() + "_t"
+
+AmqpClass.structName = lambda c: "amqp_" + c_ize(c.name) + "_properties_t"
+
+def methodApiPrototype(m):
+ fn = m.fullName()
+ info = apiMethodInfo.get(fn, [])
+
+ docs = "/**\n * %s\n *\n" % (fn)
+ docs += " * @param [in] state connection state\n"
+ docs += " * @param [in] channel the channel to do the RPC on\n"
+
+ args = []
+ for f in m.arguments:
+ n = c_ize(f.name)
+ if n in apiMethodsSuppressArgs or n in info:
+ continue
+
+ args.append(", ")
+ args.append(typeFor(m.klass.spec, f).ctype)
+ args.append(" ")
+ args.append(n)
+ docs += " * @param [in] %s %s\n" % (n, n)
+
+ docs += " * @returns %s_ok_t\n" % (fn)
+ docs += " */\n"
+
+ return "%sAMQP_PUBLIC_FUNCTION\n%s_ok_t *\nAMQP_CALL %s(amqp_connection_state_t state, amqp_channel_t channel%s)" % (docs, fn, fn, ''.join(args))
+
+AmqpMethod.apiPrototype = methodApiPrototype
+
+def cConstantName(s):
+ return 'AMQP_' + '_'.join(re.split('[- ]', s.upper()))
+
+def cFlagName(c, f):
+ return cConstantName(c.name + '_' + f.name) + '_FLAG'
+
+def genErl(spec):
+ def fieldTempList(fields):
+ return '[' + ', '.join(['F' + str(f.index) for f in fields]) + ']'
+
+ def fieldMapList(fields):
+ return ', '.join([c_ize(f.name) + " = F" + str(f.index) for f in fields])
+
+ def genLookupMethodName(m):
+ print ' case %s: return "%s";' % (m.defName(), m.defName())
+
+ def genDecodeMethodFields(m):
+ print " case %s: {" % (m.defName(),)
+ print " %s *m = (%s *) amqp_pool_alloc(pool, sizeof(%s));" % \
+ (m.structName(), m.structName(), m.structName())
+ print " if (m == NULL) { return AMQP_STATUS_NO_MEMORY; }"
+
+ emitter = BitDecoder(Emitter(" "))
+ for f in m.arguments:
+ typeFor(spec, f).decode(emitter, "m->"+c_ize(f.name))
+
+ print " *decoded = m;"
+ print " return 0;"
+ print " }"
+
+ def genDecodeProperties(c):
+ print " case %d: {" % (c.index,)
+ print " %s *p = (%s *) amqp_pool_alloc(pool, sizeof(%s));" % \
+ (c.structName(), c.structName(), c.structName())
+ print " if (p == NULL) { return AMQP_STATUS_NO_MEMORY; }"
+ print " p->_flags = flags;"
+
+ emitter = Emitter(" ")
+ for f in c.fields:
+ emitter.emit("if (flags & %s) {" % (cFlagName(c, f),))
+ typeFor(spec, f).decode(emitter, "p->"+c_ize(f.name))
+ emitter.emit("}")
+
+ print " *decoded = p;"
+ print " return 0;"
+ print " }"
+
+ def genEncodeMethodFields(m):
+ print " case %s: {" % (m.defName(),)
+ if m.arguments:
+ print " %s *m = (%s *) decoded;" % (m.structName(), m.structName())
+
+ emitter = BitEncoder(Emitter(" "))
+ for f in m.arguments:
+ typeFor(spec, f).encode(emitter, "m->"+c_ize(f.name))
+ emitter.flush()
+
+ print " return (int)offset;"
+ print " }"
+
+ def genEncodeProperties(c):
+ print " case %d: {" % (c.index,)
+ if c.fields:
+ print " %s *p = (%s *) decoded;" % (c.structName(), c.structName())
+
+ emitter = Emitter(" ")
+ for f in c.fields:
+ emitter.emit(" if (flags & %s) {" % (cFlagName(c, f),))
+ typeFor(spec, f).encode(emitter, "p->"+c_ize(f.name))
+ emitter.emit("}")
+
+ print " return (int)offset;"
+ print " }"
+
+ methods = spec.allMethods()
+
+ print """/* Generated code. Do not edit. Edit and re-run codegen.py instead.
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "amqp_private.h"
+#include
+#include
+#include
+#include
+"""
+
+ print """
+char const *amqp_constant_name(int constantNumber) {
+ switch (constantNumber) {"""
+ for (c,v,cls) in spec.constants:
+ print " case %s: return \"%s\";" % (cConstantName(c), cConstantName(c))
+ print """ default: return "(unknown)";
+ }
+}"""
+
+ print """
+amqp_boolean_t amqp_constant_is_hard_error(int constantNumber) {
+ switch (constantNumber) {"""
+ for (c,v,cls) in spec.constants:
+ if cls == 'hard-error':
+ print " case %s: return 1;" % (cConstantName(c),)
+ print """ default: return 0;
+ }
+}"""
+
+ print """
+char const *amqp_method_name(amqp_method_number_t methodNumber) {
+ switch (methodNumber) {"""
+ for m in methods: genLookupMethodName(m)
+ print """ default: return NULL;
+ }
+}"""
+
+ print """
+amqp_boolean_t amqp_method_has_content(amqp_method_number_t methodNumber) {
+ switch (methodNumber) {"""
+ for m in methods:
+ if m.hasContent:
+ print ' case %s: return 1;' % (m.defName())
+ print """ default: return 0;
+ }
+}"""
+
+ print """
+int amqp_decode_method(amqp_method_number_t methodNumber,
+ amqp_pool_t *pool,
+ amqp_bytes_t encoded,
+ void **decoded)
+{
+ size_t offset = 0;
+ uint8_t bit_buffer;
+
+ switch (methodNumber) {"""
+ for m in methods: genDecodeMethodFields(m)
+ print """ default: return AMQP_STATUS_UNKNOWN_METHOD;
+ }
+}"""
+
+ print """
+int amqp_decode_properties(uint16_t class_id,
+ amqp_pool_t *pool,
+ amqp_bytes_t encoded,
+ void **decoded)
+{
+ size_t offset = 0;
+
+ amqp_flags_t flags = 0;
+ int flagword_index = 0;
+ uint16_t partial_flags;
+
+ do {
+ if (!amqp_decode_16(encoded, &offset, &partial_flags))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ flags |= (partial_flags << (flagword_index * 16));
+ flagword_index++;
+ } while (partial_flags & 1);
+
+ switch (class_id) {"""
+ for c in spec.allClasses(): genDecodeProperties(c)
+ print """ default: return AMQP_STATUS_UNKNOWN_CLASS;
+ }
+}"""
+
+ print """
+int amqp_encode_method(amqp_method_number_t methodNumber,
+ void *decoded,
+ amqp_bytes_t encoded)
+{
+ size_t offset = 0;
+ uint8_t bit_buffer;
+
+ switch (methodNumber) {"""
+ for m in methods: genEncodeMethodFields(m)
+ print """ default: return AMQP_STATUS_UNKNOWN_METHOD;
+ }
+}"""
+
+ print """
+int amqp_encode_properties(uint16_t class_id,
+ void *decoded,
+ amqp_bytes_t encoded)
+{
+ size_t offset = 0;
+
+ /* Cheat, and get the flags out generically, relying on the
+ similarity of structure between classes */
+ amqp_flags_t flags = * (amqp_flags_t *) decoded; /* cheating! */
+
+ {
+ /* We take a copy of flags to avoid destroying it, as it is used
+ in the autogenerated code below. */
+ amqp_flags_t remaining_flags = flags;
+ do {
+ amqp_flags_t remainder = remaining_flags >> 16;
+ uint16_t partial_flags = remaining_flags & 0xFFFE;
+ if (remainder != 0) { partial_flags |= 1; }
+ if (!amqp_encode_16(encoded, &offset, partial_flags))
+ return AMQP_STATUS_BAD_AMQP_DATA;
+ remaining_flags = remainder;
+ } while (remaining_flags != 0);
+ }
+
+ switch (class_id) {"""
+ for c in spec.allClasses(): genEncodeProperties(c)
+ print """ default: return AMQP_STATUS_UNKNOWN_CLASS;
+ }
+}"""
+
+ for m in methods:
+ if not m.isSynchronous:
+ continue
+
+ info = apiMethodInfo.get(m.fullName(), [])
+ if info is False:
+ continue
+
+ print
+ print m.apiPrototype()
+ print "{"
+ print " %s req;" % (m.structName(),)
+
+ for f in m.arguments:
+ n = c_ize(f.name)
+
+ val = apiMethodsSuppressArgs.get(n)
+ if val is None and n in info:
+ val = f.defaultvalue
+
+ if val is None:
+ val = n
+ else:
+ val = typeFor(spec, f).literal(val)
+
+
+ print " req.%s = %s;" % (n, val)
+
+ reply = cConstantName(c_ize(m.klass.name) + '_' + c_ize(m.name)
+ + "_ok_method")
+ print """
+ return amqp_simple_rpc_decoded(state, channel, %s, %s, &req);
+}
+""" % (m.defName(), reply)
+
+def genHrl(spec):
+ def fieldDeclList(fields):
+ if fields:
+ return ''.join([" %s %s; /**< %s */\n" % (typeFor(spec, f).ctype,
+ c_ize(f.name), f.name)
+ for f in fields])
+ else:
+ return " char dummy; /**< Dummy field to avoid empty struct */\n"
+
+ def propDeclList(fields):
+ return ''.join([" %s %s;\n" % (typeFor(spec, f).ctype, c_ize(f.name))
+ for f in fields
+ if spec.resolveDomain(f.domain) != 'bit'])
+
+ methods = spec.allMethods()
+
+ print """/* Generated code. Do not edit. Edit and re-run codegen.py instead.
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+/** @file amqp_framing.h */
+#ifndef AMQP_FRAMING_H
+#define AMQP_FRAMING_H
+
+#include
+
+AMQP_BEGIN_DECLS
+"""
+ print "#define AMQP_PROTOCOL_VERSION_MAJOR %d /**< AMQP protocol version major */" % (spec.major)
+ print "#define AMQP_PROTOCOL_VERSION_MINOR %d /**< AMQP protocol version minor */" % (spec.minor)
+ print "#define AMQP_PROTOCOL_VERSION_REVISION %d /**< AMQP protocol version revision */" % (spec.revision)
+ print "#define AMQP_PROTOCOL_PORT %d /**< Default AMQP Port */" % (spec.port)
+
+ for (c,v,cls) in spec.constants:
+ print "#define %s %s /**< Constant: %s */" % (cConstantName(c), v, c)
+ print
+
+ print """/* Function prototypes. */
+
+/**
+ * Get constant name string from constant
+ *
+ * @param [in] constantNumber constant to get the name of
+ * @returns string describing the constant. String is managed by
+ * the library and should not be free()'d by the program
+ */
+AMQP_PUBLIC_FUNCTION
+char const *
+AMQP_CALL amqp_constant_name(int constantNumber);
+
+/**
+ * Checks to see if a constant is a hard error
+ *
+ * A hard error occurs when something severe enough
+ * happens that the connection must be closed.
+ *
+ * @param [in] constantNumber the error constant
+ * @returns true if its a hard error, false otherwise
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_boolean_t
+AMQP_CALL amqp_constant_is_hard_error(int constantNumber);
+
+/**
+ * Get method name string from method number
+ *
+ * @param [in] methodNumber the method number
+ * @returns method name string. String is managed by the library
+ * and should not be freed()'d by the program
+ */
+AMQP_PUBLIC_FUNCTION
+char const *
+AMQP_CALL amqp_method_name(amqp_method_number_t methodNumber);
+
+/**
+ * Check whether a method has content
+ *
+ * A method that has content will receive the method frame
+ * a properties frame, then 1 to N body frames
+ *
+ * @param [in] methodNumber the method number
+ * @returns true if method has content, false otherwise
+ */
+AMQP_PUBLIC_FUNCTION
+amqp_boolean_t
+AMQP_CALL amqp_method_has_content(amqp_method_number_t methodNumber);
+
+/**
+ * Decodes a method from AMQP wireformat
+ *
+ * @param [in] methodNumber the method number for the decoded parameter
+ * @param [in] pool the memory pool to allocate the decoded method from
+ * @param [in] encoded the encoded byte string buffer
+ * @param [out] decoded pointer to the decoded method struct
+ * @returns 0 on success, an error code otherwise
+ */
+AMQP_PUBLIC_FUNCTION
+int
+AMQP_CALL amqp_decode_method(amqp_method_number_t methodNumber,
+ amqp_pool_t *pool,
+ amqp_bytes_t encoded,
+ void **decoded);
+
+/**
+ * Decodes a header frame properties structure from AMQP wireformat
+ *
+ * @param [in] class_id the class id for the decoded parameter
+ * @param [in] pool the memory pool to allocate the decoded properties from
+ * @param [in] encoded the encoded byte string buffer
+ * @param [out] decoded pointer to the decoded properties struct
+ * @returns 0 on success, an error code otherwise
+ */
+AMQP_PUBLIC_FUNCTION
+int
+AMQP_CALL amqp_decode_properties(uint16_t class_id,
+ amqp_pool_t *pool,
+ amqp_bytes_t encoded,
+ void **decoded);
+
+/**
+ * Encodes a method structure in AMQP wireformat
+ *
+ * @param [in] methodNumber the method number for the decoded parameter
+ * @param [in] decoded the method structure (e.g., amqp_connection_start_t)
+ * @param [in] encoded an allocated byte buffer for the encoded method
+ * structure to be written to. If the buffer isn't large enough
+ * to hold the encoded method, an error code will be returned.
+ * @returns 0 on success, an error code otherwise.
+ */
+AMQP_PUBLIC_FUNCTION
+int
+AMQP_CALL amqp_encode_method(amqp_method_number_t methodNumber,
+ void *decoded,
+ amqp_bytes_t encoded);
+
+/**
+ * Encodes a properties structure in AMQP wireformat
+ *
+ * @param [in] class_id the class id for the decoded parameter
+ * @param [in] decoded the properties structure (e.g., amqp_basic_properties_t)
+ * @param [in] encoded an allocated byte buffer for the encoded properties to written to.
+ * If the buffer isn't large enough to hold the encoded method, an
+ * an error code will be returned
+ * @returns 0 on success, an error code otherwise.
+ */
+AMQP_PUBLIC_FUNCTION
+int
+AMQP_CALL amqp_encode_properties(uint16_t class_id,
+ void *decoded,
+ amqp_bytes_t encoded);
+"""
+
+ print "/* Method field records. */\n"
+ for m in methods:
+ methodid = m.klass.index << 16 | m.index
+ print "#define %s ((amqp_method_number_t) 0x%.08X) /**< %s.%s method id @internal %d, %d; %d */" % \
+ (m.defName(),
+ methodid,
+ m.klass.name,
+ m.name,
+ m.klass.index,
+ m.index,
+ methodid)
+ print "/** %s.%s method fields */\ntypedef struct %s_ {\n%s} %s;\n" % \
+ (m.klass.name, m.name, m.structName(), fieldDeclList(m.arguments), m.structName())
+
+ print "/* Class property records. */"
+ for c in spec.allClasses():
+ print "#define %s (0x%.04X) /**< %s class id @internal %d */" % \
+ (cConstantName(c.name + "_class"), c.index, c.name, c.index)
+ index = 0
+ for f in c.fields:
+ if index % 16 == 15:
+ index = index + 1
+ shortnum = index // 16
+ partialindex = 15 - (index % 16)
+ bitindex = shortnum * 16 + partialindex
+ print '#define %s (1 << %d) /**< %s.%s property flag */' % (cFlagName(c, f), bitindex, c.name, f.name)
+ index = index + 1
+ print "/** %s class properties */\ntypedef struct %s_ {\n amqp_flags_t _flags; /**< bit-mask of set fields */\n%s} %s;\n" % \
+ (c.name,
+ c.structName(),
+ fieldDeclList(c.fields),
+ c.structName())
+
+ print "/* API functions for methods */\n"
+
+ for m in methods:
+ if m.isSynchronous and apiMethodInfo.get(m.fullName()) is not False:
+ print "%s;" % (m.apiPrototype(),)
+
+ print """
+AMQP_END_DECLS
+
+#endif /* AMQP_FRAMING_H */"""
+
+def generateErl(specPath):
+ genErl(AmqpSpec(specPath))
+
+def generateHrl(specPath):
+ genHrl(AmqpSpec(specPath))
+
+if __name__ == "__main__":
+ do_main(generateHrl, generateErl)
diff --git a/ext/librabbitmq/librabbitmq/unix/threads.h b/ext/librabbitmq/librabbitmq/unix/threads.h
new file mode 100644
index 000000000..8a2623bbe
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/unix/threads.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012-2013 Michael Steinert
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef AMQP_THREADS_H
+#define AMQP_THREADS_H
+
+#include
+
+#endif /* AMQP_THREADS_H */
diff --git a/ext/librabbitmq/librabbitmq/win32/msinttypes/stdint.h b/ext/librabbitmq/librabbitmq/win32/msinttypes/stdint.h
new file mode 100644
index 000000000..a7437be66
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/win32/msinttypes/stdint.h
@@ -0,0 +1,245 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+#define _W64 __w64
+#else
+#define _W64
+#endif
+#endif
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+#else
+typedef signed __int8 int8_t;
+typedef signed __int16 int16_t;
+typedef signed __int32 int32_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+typedef signed __int64 intptr_t;
+typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+typedef _W64 signed int intptr_t;
+typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || \
+ defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and
+ // footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+#define INTPTR_MIN INT64_MIN
+#define INTPTR_MAX INT64_MAX
+#define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+#define INTPTR_MIN INT32_MIN
+#define INTPTR_MAX INT32_MAX
+#define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+#define PTRDIFF_MIN _I64_MIN
+#define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+#define PTRDIFF_MIN _I32_MIN
+#define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+#ifdef _WIN64 // [
+#define SIZE_MAX _UI64_MAX
+#else // _WIN64 ][
+#define SIZE_MAX _UI32_MAX
+#endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in
+#ifndef WCHAR_MIN // [
+#define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+#define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || \
+ defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/ext/librabbitmq/librabbitmq/win32/threads.c b/ext/librabbitmq/librabbitmq/win32/threads.c
new file mode 100644
index 000000000..cce315865
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/win32/threads.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2013 Michael Steinert
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "threads.h"
+
+#include
+
+DWORD pthread_self(void) { return GetCurrentThreadId(); }
+
+int pthread_mutex_init(pthread_mutex_t *mutex, void *attr) {
+ if (!mutex) {
+ return 1;
+ }
+ InitializeSRWLock(mutex);
+ return 0;
+}
+
+int pthread_mutex_lock(pthread_mutex_t *mutex) {
+ if (!mutex) {
+ return 1;
+ }
+ AcquireSRWLockExclusive(mutex);
+ return 0;
+}
+
+int pthread_mutex_unlock(pthread_mutex_t *mutex) {
+ if (!mutex) {
+ return 1;
+ }
+ ReleaseSRWLockExclusive(mutex);
+ return 0;
+}
+
+int pthread_mutex_destroy(pthread_mutex_t *mutex) {
+ /* SRW's do not require destruction. */
+ return 0;
+}
diff --git a/ext/librabbitmq/librabbitmq/win32/threads.h b/ext/librabbitmq/librabbitmq/win32/threads.h
new file mode 100644
index 000000000..69371f39b
--- /dev/null
+++ b/ext/librabbitmq/librabbitmq/win32/threads.h
@@ -0,0 +1,52 @@
+/*
+ * Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
+ * All Rights Reserved.
+ *
+ * Portions created by Michael Steinert are Copyright (c) 2012-2013 Michael
+ * Steinert. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef AMQP_THREAD_H
+#define AMQP_THREAD_H
+
+#if !defined(WINVER) || defined(__MINGW32__) || defined(__MINGW64__)
+#ifdef WINVER
+#undef WINVER
+#endif
+/* Windows Vista or newer */
+#define WINVER 0x0600
+#endif
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+
+typedef SRWLOCK pthread_mutex_t;
+#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT;
+
+DWORD pthread_self(void);
+
+int pthread_mutex_init(pthread_mutex_t *, void *attr);
+int pthread_mutex_lock(pthread_mutex_t *);
+int pthread_mutex_unlock(pthread_mutex_t *);
+int pthread_mutex_destroy(pthread_mutex_t *);
+
+#endif /* AMQP_THREAD_H */
diff --git a/ext/librabbitmq/tests/CMakeLists.txt b/ext/librabbitmq/tests/CMakeLists.txt
new file mode 100644
index 000000000..cf042b045
--- /dev/null
+++ b/ext/librabbitmq/tests/CMakeLists.txt
@@ -0,0 +1,47 @@
+include_directories(${LIBRABBITMQ_INCLUDE_DIRS})
+
+if (MSVC)
+ # No version of MSVC has inttypes.h, this uses the msinttypes
+ # Note this includes stdint.h which is either in
+ # ../librabbitmq/win32/msinttypes or in a standard location
+ include_directories(win32/msinttypes)
+endif (MSVC)
+
+add_definitions(-DHAVE_CONFIG_H)
+add_definitions(-DAMQP_STATIC)
+
+add_executable(test_parse_url test_parse_url.c)
+target_link_libraries(test_parse_url rabbitmq-static)
+add_test(parse_url test_parse_url)
+
+add_executable(test_tables test_tables.c)
+target_link_libraries(test_tables rabbitmq-static)
+add_test(tables test_tables)
+configure_file(test_tables.expected ${CMAKE_CURRENT_BINARY_DIR}/tests/test_tables.expected COPYONLY)
+
+add_executable(test_hostcheck
+ test_hostcheck.c
+ ../librabbitmq/amqp_hostcheck.c)
+add_test(hostcheck test_hostcheck)
+
+add_executable(test_status_enum
+ test_status_enum.c)
+target_link_libraries(test_status_enum rabbitmq-static)
+add_test(status_enum test_status_enum)
+
+add_executable(test_basic
+ test_basic.c)
+target_link_libraries(test_basic rabbitmq-static)
+
+if (NOT APPLE)
+ add_test(basic test_basic)
+endif()
+
+add_executable(test_sasl_mechanism test_sasl_mechanism.c)
+target_link_libraries(test_sasl_mechanism rabbitmq-static)
+add_test(sasl_mechanism test_sasl_mechanism)
+
+add_executable(test_merge_capabilities test_merge_capabilities.c)
+target_link_libraries(test_merge_capabilities rabbitmq-static)
+add_test(merge_capabilities test_merge_capabilities)
+
diff --git a/ext/librabbitmq/tests/test_basic.c b/ext/librabbitmq/tests/test_basic.c
new file mode 100644
index 000000000..a7de0446f
--- /dev/null
+++ b/ext/librabbitmq/tests/test_basic.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2017 Simon Giesecke
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "amqp.h"
+#include "amqp_tcp_socket.h"
+#include "amqp_time.h"
+
+#include
+#include
+#include
+
+#ifdef _WIN32
+#include
+#else
+#include
+#endif
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+#include
+
+static const int fixed_channel_id = 1;
+static const char test_queue_name[] = "test_queue";
+
+amqp_connection_state_t setup_connection_and_channel(void) {
+ amqp_connection_state_t connection_state_ = amqp_new_connection();
+
+ amqp_socket_t *socket = amqp_tcp_socket_new(connection_state_);
+ assert(socket);
+
+ int rc = amqp_socket_open(socket, "localhost", AMQP_PROTOCOL_PORT);
+ assert(rc == AMQP_STATUS_OK);
+
+ amqp_rpc_reply_t rpc_reply = amqp_login(
+ connection_state_, "/", 1, AMQP_DEFAULT_FRAME_SIZE,
+ AMQP_DEFAULT_HEARTBEAT, AMQP_SASL_METHOD_PLAIN, "guest", "guest");
+ assert(rpc_reply.reply_type == AMQP_RESPONSE_NORMAL);
+
+ amqp_channel_open_ok_t *res =
+ amqp_channel_open(connection_state_, fixed_channel_id);
+ assert(res != NULL);
+
+ return connection_state_;
+}
+
+void close_and_destroy_connection(amqp_connection_state_t connection_state_) {
+ amqp_rpc_reply_t rpc_reply =
+ amqp_connection_close(connection_state_, AMQP_REPLY_SUCCESS);
+ assert(rpc_reply.reply_type == AMQP_RESPONSE_NORMAL);
+
+ int rc = amqp_destroy_connection(connection_state_);
+ assert(rc == AMQP_STATUS_OK);
+}
+
+void basic_publish(amqp_connection_state_t connectionState_,
+ const char *message_) {
+ amqp_bytes_t message_bytes = amqp_cstring_bytes(message_);
+
+ amqp_basic_properties_t properties;
+ properties._flags = 0;
+
+ properties._flags |= AMQP_BASIC_DELIVERY_MODE_FLAG;
+ properties.delivery_mode = AMQP_DELIVERY_NONPERSISTENT;
+
+ int retval = amqp_basic_publish(
+ connectionState_, fixed_channel_id, amqp_cstring_bytes(""),
+ amqp_cstring_bytes(test_queue_name),
+ /* mandatory=*/1,
+ /* immediate=*/0, /* RabbitMQ 3.x does not support the "immediate" flag
+ according to
+ https://www.rabbitmq.com/specification.html */
+ &properties, message_bytes);
+
+ assert(retval == 0);
+}
+
+void queue_declare(amqp_connection_state_t connection_state_,
+ const char *queue_name_) {
+ amqp_queue_declare_ok_t *res = amqp_queue_declare(
+ connection_state_, fixed_channel_id, amqp_cstring_bytes(queue_name_),
+ /*passive*/ 0,
+ /*durable*/ 0,
+ /*exclusive*/ 0,
+ /*auto_delete*/ 1, amqp_empty_table);
+ assert(res != NULL);
+}
+
+char *basic_get(amqp_connection_state_t connection_state_,
+ const char *queue_name_, uint64_t *out_body_size_) {
+ amqp_rpc_reply_t rpc_reply;
+ amqp_time_t deadline;
+ struct timeval timeout = {5, 0};
+ int time_rc = amqp_time_from_now(&deadline, &timeout);
+ assert(time_rc == AMQP_STATUS_OK);
+
+ do {
+ rpc_reply = amqp_basic_get(connection_state_, fixed_channel_id,
+ amqp_cstring_bytes(queue_name_), /*no_ack*/ 1);
+ } while (rpc_reply.reply_type == AMQP_RESPONSE_NORMAL &&
+ rpc_reply.reply.id == AMQP_BASIC_GET_EMPTY_METHOD &&
+ amqp_time_has_past(deadline) == AMQP_STATUS_OK);
+
+ assert(rpc_reply.reply_type == AMQP_RESPONSE_NORMAL);
+ assert(rpc_reply.reply.id == AMQP_BASIC_GET_OK_METHOD);
+
+ amqp_message_t message;
+ rpc_reply =
+ amqp_read_message(connection_state_, fixed_channel_id, &message, 0);
+ assert(rpc_reply.reply_type == AMQP_RESPONSE_NORMAL);
+
+ char *body = malloc(message.body.len);
+ memcpy(body, message.body.bytes, message.body.len);
+ *out_body_size_ = message.body.len;
+ amqp_destroy_message(&message);
+
+ return body;
+}
+
+void publish_and_basic_get_message(const char *msg_to_publish) {
+ amqp_connection_state_t connection_state = setup_connection_and_channel();
+
+ queue_declare(connection_state, test_queue_name);
+ basic_publish(connection_state, msg_to_publish);
+
+ uint64_t body_size;
+ char *msg = basic_get(connection_state, test_queue_name, &body_size);
+
+ assert(body_size == strlen(msg_to_publish));
+ assert(strncmp(msg_to_publish, msg, body_size) == 0);
+ free(msg);
+
+ close_and_destroy_connection(connection_state);
+}
+
+char *consume_message(amqp_connection_state_t connection_state_,
+ const char *queue_name_, uint64_t *out_body_size_) {
+ amqp_basic_consume_ok_t *result =
+ amqp_basic_consume(connection_state_, fixed_channel_id,
+ amqp_cstring_bytes(queue_name_), amqp_empty_bytes,
+ /*no_local*/ 0,
+ /*no_ack*/ 1,
+ /*exclusive*/ 0, amqp_empty_table);
+ assert(result != NULL);
+
+ amqp_envelope_t envelope;
+ struct timeval timeout = {5, 0};
+ amqp_rpc_reply_t rpc_reply =
+ amqp_consume_message(connection_state_, &envelope, &timeout, 0);
+ assert(rpc_reply.reply_type == AMQP_RESPONSE_NORMAL);
+
+ *out_body_size_ = envelope.message.body.len;
+ char *body = malloc(*out_body_size_);
+ if (*out_body_size_) {
+ memcpy(body, envelope.message.body.bytes, *out_body_size_);
+ }
+
+ amqp_destroy_envelope(&envelope);
+ return body;
+}
+
+void publish_and_consume_message(const char *msg_to_publish) {
+ amqp_connection_state_t connection_state = setup_connection_and_channel();
+
+ queue_declare(connection_state, test_queue_name);
+ basic_publish(connection_state, msg_to_publish);
+
+ uint64_t body_size;
+ char *msg = consume_message(connection_state, test_queue_name, &body_size);
+
+ assert(body_size == strlen(msg_to_publish));
+ assert(strncmp(msg_to_publish, msg, body_size) == 0);
+ free(msg);
+
+ close_and_destroy_connection(connection_state);
+}
+
+int main(void) {
+ publish_and_basic_get_message("");
+ publish_and_basic_get_message("TEST");
+
+ publish_and_consume_message("");
+ publish_and_consume_message("TEST");
+
+ return 0;
+}
diff --git a/ext/librabbitmq/tests/test_hostcheck.c b/ext/librabbitmq/tests/test_hostcheck.c
new file mode 100644
index 000000000..24c0d6c28
--- /dev/null
+++ b/ext/librabbitmq/tests/test_hostcheck.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 Michael Steinert
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "amqp_hostcheck.h"
+
+#include
+#include
+
+static void hostcheck_success(const char *match_pattern, const char *url) {
+ int ok;
+
+ ok = amqp_hostcheck(match_pattern, url);
+ if (!ok) {
+ fprintf(stderr, "Expected hostname check to pass, but didn't: %s (%s)\n",
+ url, match_pattern);
+ abort();
+ }
+
+ fprintf(stdout, "ok: [success] %s, %s\n", url, match_pattern);
+}
+
+static void hostcheck_fail(const char *match_pattern, const char *url) {
+ int ok;
+
+ ok = amqp_hostcheck(match_pattern, url);
+ if (ok) {
+ fprintf(stderr, "Expected hostname check to fail, but didn't: %s (%s)\n",
+ url, match_pattern);
+ abort();
+ }
+
+ fprintf(stdout, "ok: [fail] %s, %s\n", url, match_pattern);
+}
+
+int main(void) {
+ hostcheck_success("www.rabbitmq.com", "www.rabbitmq.com");
+ hostcheck_success("www.rabbitmq.com", "wWw.RaBbItMq.CoM");
+ hostcheck_success("*.rabbitmq.com", "wWw.RaBbItMq.CoM");
+ hostcheck_fail("rabbitmq.com", "www.rabbitmq.com");
+ hostcheck_success("*.rabbitmq.com", "www.rabbitmq.com");
+ hostcheck_fail("*.com", "www.rabbitmq.com");
+ hostcheck_fail("*.rabbitmq.com", "long.url.rabbitmq.com");
+ hostcheck_success("*.url.rabbitmq.com", "long.url.rabbitmq.com");
+
+ return 0;
+}
diff --git a/ext/librabbitmq/tests/test_merge_capabilities.c b/ext/librabbitmq/tests/test_merge_capabilities.c
new file mode 100644
index 000000000..d62fcd316
--- /dev/null
+++ b/ext/librabbitmq/tests/test_merge_capabilities.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2015 Alan Antonuk. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "amqp_socket.h"
+#include "amqp_table.h"
+
+#include
+#include
+
+static int compare_bytes(amqp_bytes_t l, amqp_bytes_t r);
+static int compare_amqp_table_entry(amqp_table_entry_t result,
+ amqp_table_entry_t expect);
+static int compare_field_value(amqp_field_value_t result,
+ amqp_field_value_t expect);
+static int compare_amqp_table(amqp_table_t* result, amqp_table_t* expect);
+
+static int compare_bytes(amqp_bytes_t l, amqp_bytes_t r) {
+ if (l.len == r.len &&
+ (l.bytes == r.bytes || 0 == memcmp(l.bytes, r.bytes, l.len))) {
+ return 1;
+ }
+ return 0;
+}
+
+static int compare_amqp_table_entry(amqp_table_entry_t result,
+ amqp_table_entry_t expect) {
+ if (!compare_bytes(result.key, expect.key)) {
+ return 0;
+ }
+ return compare_field_value(result.value, expect.value);
+}
+
+static int compare_field_value(amqp_field_value_t result,
+ amqp_field_value_t expect) {
+ if (result.kind != expect.kind) {
+ return 0;
+ }
+ switch (result.kind) {
+ case AMQP_FIELD_KIND_BOOLEAN:
+ return result.value.boolean == expect.value.boolean;
+ case AMQP_FIELD_KIND_I8:
+ return result.value.i8 == expect.value.i8;
+ case AMQP_FIELD_KIND_U8:
+ return result.value.u8 == expect.value.u8;
+ case AMQP_FIELD_KIND_I16:
+ return result.value.i16 == expect.value.i16;
+ case AMQP_FIELD_KIND_U16:
+ return result.value.u16 == expect.value.u16;
+ case AMQP_FIELD_KIND_I32:
+ return result.value.i32 == expect.value.i32;
+ case AMQP_FIELD_KIND_U32:
+ return result.value.u32 == expect.value.u32;
+ case AMQP_FIELD_KIND_I64:
+ return result.value.i64 == expect.value.i64;
+ case AMQP_FIELD_KIND_U64:
+ case AMQP_FIELD_KIND_TIMESTAMP:
+ return result.value.u64 == expect.value.u64;
+ case AMQP_FIELD_KIND_F32:
+ return result.value.f32 == expect.value.f32;
+ case AMQP_FIELD_KIND_F64:
+ return result.value.f64 == expect.value.f64;
+ case AMQP_FIELD_KIND_DECIMAL:
+ return !memcmp(&result.value.decimal, &expect.value.decimal,
+ sizeof(expect.value.decimal));
+ case AMQP_FIELD_KIND_UTF8:
+ case AMQP_FIELD_KIND_BYTES:
+ return compare_bytes(result.value.bytes, expect.value.bytes);
+ case AMQP_FIELD_KIND_ARRAY: {
+ int i;
+ if (result.value.array.num_entries != expect.value.array.num_entries) {
+ return 0;
+ }
+ for (i = 0; i < result.value.array.num_entries; ++i) {
+ if (!compare_field_value(result.value.array.entries[i],
+ expect.value.array.entries[i])) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ case AMQP_FIELD_KIND_TABLE:
+ return compare_amqp_table(&result.value.table, &expect.value.table);
+ case AMQP_FIELD_KIND_VOID:
+ return 1;
+ }
+ return 1;
+}
+
+static int compare_amqp_table(amqp_table_t* result, amqp_table_t* expect) {
+ int i;
+
+ if (result->num_entries != expect->num_entries) {
+ return 0;
+ }
+
+ for (i = 0; i < expect->num_entries; ++i) {
+ if (!compare_amqp_table_entry(expect->entries[i], result->entries[i])) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void test_merge_capabilities(amqp_table_t* base, amqp_table_t* add,
+ amqp_table_t* expect) {
+ amqp_pool_t pool;
+ amqp_table_t result;
+ int res;
+ init_amqp_pool(&pool, 4096);
+
+ res = amqp_merge_capabilities(base, add, &result, &pool);
+ if (AMQP_STATUS_OK != res) {
+ fprintf(stderr, "amqp_merge_capabilities returned !ok: %d\n", res);
+ abort();
+ }
+
+ if (!compare_amqp_table(&result, expect)) {
+ fprintf(stderr, "amqp_merge_capabilities incorrect result.\n");
+ abort();
+ }
+ empty_amqp_pool(&pool);
+ return;
+}
+
+int main(void) {
+ {
+ amqp_table_t sub_base;
+ amqp_table_t sub_add;
+ amqp_table_t sub_expect;
+ amqp_table_t base;
+ amqp_table_t add;
+ amqp_table_t expect;
+
+ amqp_table_entry_t sub_base_entries[1];
+ amqp_table_entry_t sub_add_entries[2];
+ amqp_table_entry_t sub_expect_entries[2];
+
+ amqp_table_entry_t base_entries[3];
+ amqp_table_entry_t add_entries[3];
+ amqp_table_entry_t expect_entries[4];
+
+ sub_base_entries[0] = amqp_table_construct_utf8_entry("foo", "bar");
+ sub_base.num_entries =
+ sizeof(sub_base_entries) / sizeof(amqp_table_entry_t);
+ sub_base.entries = sub_base_entries;
+
+ sub_add_entries[0] = amqp_table_construct_utf8_entry("something", "else");
+ sub_add_entries[1] = amqp_table_construct_utf8_entry("foo", "baz");
+ sub_add.num_entries = sizeof(sub_add_entries) / sizeof(amqp_table_entry_t);
+ sub_add.entries = sub_add_entries;
+
+ sub_expect_entries[0] = amqp_table_construct_utf8_entry("foo", "baz");
+ sub_expect_entries[1] =
+ amqp_table_construct_utf8_entry("something", "else");
+ sub_expect.num_entries =
+ sizeof(sub_expect_entries) / sizeof(amqp_table_entry_t);
+ sub_expect.entries = sub_expect_entries;
+
+ base_entries[0] = amqp_table_construct_utf8_entry("product", "1.0");
+ base_entries[1] = amqp_table_construct_utf8_entry("nooverride", "yeah");
+ base_entries[2] = amqp_table_construct_table_entry("props", &sub_base);
+ base.num_entries = sizeof(base_entries) / sizeof(amqp_table_entry_t);
+ base.entries = base_entries;
+
+ add_entries[0] = amqp_table_construct_bool_entry("bool_entry", 1);
+ add_entries[1] = amqp_table_construct_utf8_entry("product", "2.0");
+ add_entries[2] = amqp_table_construct_table_entry("props", &sub_add);
+ add.num_entries = sizeof(add_entries) / sizeof(amqp_table_entry_t);
+ add.entries = add_entries;
+
+ expect_entries[0] = amqp_table_construct_utf8_entry("product", "2.0"),
+ expect_entries[1] = amqp_table_construct_utf8_entry("nooverride", "yeah"),
+ expect_entries[2] = amqp_table_construct_table_entry("props", &sub_expect);
+ expect_entries[3] = amqp_table_construct_bool_entry("bool_entry", 1);
+ expect.num_entries = sizeof(expect_entries) / sizeof(amqp_table_entry_t);
+ expect.entries = expect_entries;
+
+ test_merge_capabilities(&base, &add, &expect);
+ }
+ fprintf(stderr, "ok\n");
+ return 0;
+}
diff --git a/ext/librabbitmq/tests/test_parse_url.c b/ext/librabbitmq/tests/test_parse_url.c
new file mode 100644
index 000000000..9cdc87c10
--- /dev/null
+++ b/ext/librabbitmq/tests/test_parse_url.c
@@ -0,0 +1,220 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include "config.h"
+
+#ifdef _MSC_VER
+/* MSVC complains about strdup being deprecated in favor of _strdup */
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#include
+#include
+#include
+
+#include
+
+#include
+
+static void match_string(const char *what, const char *expect,
+ const char *got) {
+ if (strcmp(got, expect)) {
+ fprintf(stderr, "Expected %s '%s', got '%s'\n", what, expect, got);
+ abort();
+ }
+}
+
+static void match_int(const char *what, int expect, int got) {
+ if (got != expect) {
+ fprintf(stderr, "Expected %s '%d', got '%d'\n", what, expect, got);
+ abort();
+ }
+}
+
+static void parse_success(const char *url, const char *user,
+ const char *password, const char *host, int port,
+ const char *vhost) {
+ char *s = strdup(url);
+ struct amqp_connection_info ci;
+ int res;
+
+ res = amqp_parse_url(s, &ci);
+ if (res) {
+ fprintf(stderr, "Expected to successfully parse URL, but didn't: %s (%s)\n",
+ url, amqp_error_string2(res));
+ abort();
+ }
+
+ match_string("user", user, ci.user);
+ match_string("password", password, ci.password);
+ match_string("host", host, ci.host);
+ match_int("port", port, ci.port);
+ match_string("vhost", vhost, ci.vhost);
+
+ free(s);
+}
+
+static void parse_fail(const char *url) {
+ char *s = strdup(url);
+ struct amqp_connection_info ci;
+
+ amqp_default_connection_info(&ci);
+ if (amqp_parse_url(s, &ci) >= 0) {
+ fprintf(stderr, "Expected to fail parsing URL, but didn't: %s\n", url);
+ abort();
+ }
+
+ free(s);
+}
+
+int main(void) {
+ /* From the spec */
+ parse_success("amqp://user:pass@host:10000/vhost", "user", "pass", "host",
+ 10000, "vhost");
+ parse_success("amqps://user:pass@host:10000/vhost", "user", "pass", "host",
+ 10000, "vhost");
+
+ parse_success("amqp://user%61:%61pass@ho%61st:10000/v%2fhost", "usera",
+ "apass", "hoast", 10000, "v/host");
+ parse_success("amqps://user%61:%61pass@ho%61st:10000/v%2fhost", "usera",
+ "apass", "hoast", 10000, "v/host");
+
+ parse_success("amqp://", "guest", "guest", "localhost", 5672, "/");
+ parse_success("amqps://", "guest", "guest", "localhost", 5671, "/");
+
+ parse_success("amqp://:@/", "", "", "localhost", 5672, "");
+ parse_success("amqps://:@/", "", "", "localhost", 5671, "");
+
+ parse_success("amqp://user@", "user", "guest", "localhost", 5672, "/");
+ parse_success("amqps://user@", "user", "guest", "localhost", 5671, "/");
+
+ parse_success("amqp://user:pass@", "user", "pass", "localhost", 5672, "/");
+ parse_success("amqps://user:pass@", "user", "pass", "localhost", 5671, "/");
+
+ parse_success("amqp://host", "guest", "guest", "host", 5672, "/");
+ parse_success("amqps://host", "guest", "guest", "host", 5671, "/");
+
+ parse_success("amqp://:10000", "guest", "guest", "localhost", 10000, "/");
+ parse_success("amqps://:10000", "guest", "guest", "localhost", 10000, "/");
+
+ parse_success("amqp:///vhost", "guest", "guest", "localhost", 5672, "vhost");
+ parse_success("amqps:///vhost", "guest", "guest", "localhost", 5671, "vhost");
+
+ parse_success("amqp://host/", "guest", "guest", "host", 5672, "");
+ parse_success("amqps://host/", "guest", "guest", "host", 5671, "");
+
+ parse_success("amqp://host/%2f", "guest", "guest", "host", 5672, "/");
+ parse_success("amqps://host/%2f", "guest", "guest", "host", 5671, "/");
+
+ parse_success("amqp://[::1]", "guest", "guest", "::1", 5672, "/");
+ parse_success("amqps://[::1]", "guest", "guest", "::1", 5671, "/");
+
+ /* Various other success cases */
+ parse_success("amqp://host:100", "guest", "guest", "host", 100, "/");
+ parse_success("amqps://host:100", "guest", "guest", "host", 100, "/");
+
+ parse_success("amqp://[::1]:100", "guest", "guest", "::1", 100, "/");
+ parse_success("amqps://[::1]:100", "guest", "guest", "::1", 100, "/");
+
+ parse_success("amqp://host/blah", "guest", "guest", "host", 5672, "blah");
+ parse_success("amqps://host/blah", "guest", "guest", "host", 5671, "blah");
+
+ parse_success("amqp://host:100/blah", "guest", "guest", "host", 100, "blah");
+ parse_success("amqps://host:100/blah", "guest", "guest", "host", 100, "blah");
+
+ parse_success("amqp://:100/blah", "guest", "guest", "localhost", 100, "blah");
+ parse_success("amqps://:100/blah", "guest", "guest", "localhost", 100,
+ "blah");
+
+ parse_success("amqp://[::1]/blah", "guest", "guest", "::1", 5672, "blah");
+ parse_success("amqps://[::1]/blah", "guest", "guest", "::1", 5671, "blah");
+
+ parse_success("amqp://[::1]:100/blah", "guest", "guest", "::1", 100, "blah");
+ parse_success("amqps://[::1]:100/blah", "guest", "guest", "::1", 100, "blah");
+
+ parse_success("amqp://user:pass@host", "user", "pass", "host", 5672, "/");
+ parse_success("amqps://user:pass@host", "user", "pass", "host", 5671, "/");
+
+ parse_success("amqp://user:pass@host:100", "user", "pass", "host", 100, "/");
+ parse_success("amqps://user:pass@host:100", "user", "pass", "host", 100, "/");
+
+ parse_success("amqp://user:pass@:100", "user", "pass", "localhost", 100, "/");
+ parse_success("amqps://user:pass@:100", "user", "pass", "localhost", 100,
+ "/");
+
+ parse_success("amqp://user:pass@[::1]", "user", "pass", "::1", 5672, "/");
+ parse_success("amqps://user:pass@[::1]", "user", "pass", "::1", 5671, "/");
+
+ parse_success("amqp://user:pass@[::1]:100", "user", "pass", "::1", 100, "/");
+ parse_success("amqps://user:pass@[::1]:100", "user", "pass", "::1", 100, "/");
+
+ /* Various failure cases */
+ parse_fail("http://www.rabbitmq.com");
+
+ parse_fail("amqp://foo:bar:baz");
+ parse_fail("amqps://foo:bar:baz");
+
+ parse_fail("amqp://foo[::1]");
+ parse_fail("amqps://foo[::1]");
+
+ parse_fail("amqp://foo[::1]");
+ parse_fail("amqps://foo[::1]");
+
+ parse_fail("amqp://foo:[::1]");
+ parse_fail("amqps://foo:[::1]");
+
+ parse_fail("amqp://[::1]foo");
+ parse_fail("amqps://[::1]foo");
+
+ parse_fail("amqp://foo:1000xyz");
+ parse_fail("amqps://foo:1000xyz");
+
+ parse_fail("amqp://foo:1000000");
+ parse_fail("amqps://foo:1000000");
+
+ parse_fail("amqp://foo/bar/baz");
+ parse_fail("amqps://foo/bar/baz");
+
+ parse_fail("amqp://foo%1");
+ parse_fail("amqps://foo%1");
+
+ parse_fail("amqp://foo%1x");
+ parse_fail("amqps://foo%1x");
+
+ parse_fail("amqp://foo%xy");
+ parse_fail("amqps://foo%xy");
+
+ return 0;
+}
diff --git a/ext/librabbitmq/tests/test_sasl_mechanism.c b/ext/librabbitmq/tests/test_sasl_mechanism.c
new file mode 100644
index 000000000..78482198f
--- /dev/null
+++ b/ext/librabbitmq/tests/test_sasl_mechanism.c
@@ -0,0 +1,70 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#include
+#include
+#include
+
+#include
+
+static void parse_success(amqp_bytes_t mechanisms,
+ amqp_sasl_method_enum method) {
+ if (!sasl_mechanism_in_list(mechanisms, method)) {
+ fprintf(stderr, "Expected to find mechanism in list, but didn't: %s\n",
+ (char *)mechanisms.bytes);
+ abort();
+ }
+}
+
+static void parse_fail(amqp_bytes_t mechanisms, amqp_sasl_method_enum method) {
+ if (sasl_mechanism_in_list(mechanisms, method)) {
+ fprintf(stderr,
+ "Expected the mechanism not on the list, but it was present: %s\n",
+ (char *)mechanisms.bytes);
+ abort();
+ }
+}
+
+int main(void) {
+ parse_success(amqp_cstring_bytes("DIGEST-MD5 CRAM-MD5 LOGIN PLAIN"),
+ AMQP_SASL_METHOD_PLAIN);
+ parse_fail(amqp_cstring_bytes("DIGEST-MD5 CRAM-MD5 LOGIN PLAIN"),
+ AMQP_SASL_METHOD_EXTERNAL);
+ parse_success(amqp_cstring_bytes("DIGEST-MD5 CRAM-MD5 EXTERNAL"),
+ AMQP_SASL_METHOD_EXTERNAL);
+ parse_fail(amqp_cstring_bytes("DIGEST-MD5 CRAM-MD5 EXTERNAL"),
+ AMQP_SASL_METHOD_PLAIN);
+ return 0;
+}
diff --git a/ext/librabbitmq/tests/test_status_enum.c b/ext/librabbitmq/tests/test_status_enum.c
new file mode 100644
index 000000000..2f2dbd7f6
--- /dev/null
+++ b/ext/librabbitmq/tests/test_status_enum.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 Alan Antonuk
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "amqp.h"
+
+#include
+#include
+#include
+
+static void check_errorstrings(amqp_status_enum start, amqp_status_enum end) {
+ int i;
+ for (i = start; i > end; --i) {
+ const char* err = amqp_error_string2(i);
+ if (0 == strcmp(err, "(unknown error)")) {
+ printf("amqp_status_enum value %s%X", i < 0 ? "-" : "", (unsigned)i);
+ abort();
+ }
+ }
+}
+
+int main(void) {
+ check_errorstrings(AMQP_STATUS_OK, _AMQP_STATUS_NEXT_VALUE);
+ check_errorstrings(AMQP_STATUS_TCP_ERROR, _AMQP_STATUS_TCP_NEXT_VALUE);
+ check_errorstrings(AMQP_STATUS_SSL_ERROR, _AMQP_STATUS_SSL_NEXT_VALUE);
+
+ return 0;
+}
diff --git a/ext/librabbitmq/tests/test_tables.c b/ext/librabbitmq/tests/test_tables.c
new file mode 100644
index 000000000..89ece6b47
--- /dev/null
+++ b/ext/librabbitmq/tests/test_tables.c
@@ -0,0 +1,466 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef _MSC_VER
+#define _USE_MATH_DEFINES
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+void die(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ abort();
+}
+
+static void dump_indent(int indent, FILE *out) {
+ int i;
+
+ for (i = 0; i < indent; i++) {
+ fputc(' ', out);
+ }
+}
+
+static void dump_value(int indent, amqp_field_value_t v, FILE *out) {
+ int i;
+
+ dump_indent(indent, out);
+ fputc(v.kind, out);
+
+ switch (v.kind) {
+ case AMQP_FIELD_KIND_BOOLEAN:
+ fputs(v.value.boolean ? " true\n" : " false\n", out);
+ break;
+
+ case AMQP_FIELD_KIND_I8:
+ fprintf(out, " %" PRId8 "\n", v.value.i8);
+ break;
+
+ case AMQP_FIELD_KIND_U8:
+ fprintf(out, " %" PRIu8 "\n", v.value.u8);
+ break;
+
+ case AMQP_FIELD_KIND_I16:
+ fprintf(out, " %" PRId16 "\n", v.value.i16);
+ break;
+
+ case AMQP_FIELD_KIND_U16:
+ fprintf(out, " %" PRIu16 "\n", v.value.u16);
+ break;
+
+ case AMQP_FIELD_KIND_I32:
+ fprintf(out, " %" PRId32 "\n", v.value.i32);
+ break;
+
+ case AMQP_FIELD_KIND_U32:
+ fprintf(out, " %" PRIu32 "\n", v.value.u32);
+ break;
+
+ case AMQP_FIELD_KIND_I64:
+ fprintf(out, " %" PRId64 "\n", v.value.i64);
+ break;
+
+ case AMQP_FIELD_KIND_F32:
+ fprintf(out, " %g\n", (double)v.value.f32);
+ break;
+
+ case AMQP_FIELD_KIND_F64:
+ fprintf(out, " %g\n", v.value.f64);
+ break;
+
+ case AMQP_FIELD_KIND_DECIMAL:
+ fprintf(out, " %u:::%u\n", v.value.decimal.decimals,
+ v.value.decimal.value);
+ break;
+
+ case AMQP_FIELD_KIND_UTF8:
+ fprintf(out, " %.*s\n", (int)v.value.bytes.len,
+ (char *)v.value.bytes.bytes);
+ break;
+
+ case AMQP_FIELD_KIND_BYTES:
+ fputc(' ', out);
+ for (i = 0; i < (int)v.value.bytes.len; i++) {
+ fprintf(out, "%02x", ((char *)v.value.bytes.bytes)[i]);
+ }
+
+ fputc('\n', out);
+ break;
+
+ case AMQP_FIELD_KIND_ARRAY:
+ fputc('\n', out);
+ for (i = 0; i < v.value.array.num_entries; i++) {
+ dump_value(indent + 2, v.value.array.entries[i], out);
+ }
+
+ break;
+
+ case AMQP_FIELD_KIND_TIMESTAMP:
+ fprintf(out, " %" PRIu64 "\n", v.value.u64);
+ break;
+
+ case AMQP_FIELD_KIND_TABLE:
+ fputc('\n', out);
+ for (i = 0; i < v.value.table.num_entries; i++) {
+ dump_indent(indent + 2, out);
+ fprintf(out, "%.*s ->\n", (int)v.value.table.entries[i].key.len,
+ (char *)v.value.table.entries[i].key.bytes);
+ dump_value(indent + 4, v.value.table.entries[i].value, out);
+ }
+
+ break;
+
+ case AMQP_FIELD_KIND_VOID:
+ fputc('\n', out);
+ break;
+
+ default:
+ fprintf(out, "???\n");
+ break;
+ }
+}
+
+static void test_dump_value(FILE *out) {
+ amqp_table_entry_t entries[8];
+ amqp_table_t table;
+ amqp_field_value_t val;
+
+ entries[0].key = amqp_cstring_bytes("zebra");
+ entries[0].value.kind = AMQP_FIELD_KIND_UTF8;
+ entries[0].value.value.bytes = amqp_cstring_bytes("last");
+
+ entries[1].key = amqp_cstring_bytes("aardvark");
+ entries[1].value.kind = AMQP_FIELD_KIND_UTF8;
+ entries[1].value.value.bytes = amqp_cstring_bytes("first");
+
+ entries[2].key = amqp_cstring_bytes("middle");
+ entries[2].value.kind = AMQP_FIELD_KIND_UTF8;
+ entries[2].value.value.bytes = amqp_cstring_bytes("third");
+
+ entries[3].key = amqp_cstring_bytes("number");
+ entries[3].value.kind = AMQP_FIELD_KIND_I32;
+ entries[3].value.value.i32 = 1234;
+
+ entries[4].key = amqp_cstring_bytes("decimal");
+ entries[4].value.kind = AMQP_FIELD_KIND_DECIMAL;
+ entries[4].value.value.decimal.decimals = 2;
+ entries[4].value.value.decimal.value = 1234;
+
+ entries[5].key = amqp_cstring_bytes("time");
+ entries[5].value.kind = AMQP_FIELD_KIND_TIMESTAMP;
+ entries[5].value.value.u64 = 1234123412341234;
+
+ entries[6].key = amqp_cstring_bytes("beta");
+ entries[6].value.kind = AMQP_FIELD_KIND_UTF8;
+ entries[6].value.value.bytes = amqp_cstring_bytes("second");
+
+ entries[7].key = amqp_cstring_bytes("wombat");
+ entries[7].value.kind = AMQP_FIELD_KIND_UTF8;
+ entries[7].value.value.bytes = amqp_cstring_bytes("fourth");
+
+ table.num_entries = 8;
+ table.entries = entries;
+
+ qsort(table.entries, table.num_entries, sizeof(amqp_table_entry_t),
+ &amqp_table_entry_cmp);
+
+ val.kind = AMQP_FIELD_KIND_TABLE;
+ val.value.table = table;
+
+ dump_value(0, val, out);
+}
+
+static uint8_t pre_encoded_table[] = {
+ 0x00, 0x00, 0x00, 0xff, 0x07, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x74, 0x72,
+ 0x53, 0x00, 0x00, 0x00, 0x15, 0x48, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73,
+ 0x20, 0x61, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x69,
+ 0x6e, 0x67, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x69, 0x6e, 0x74,
+ 0x49, 0x00, 0x00, 0x30, 0x39, 0x07, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61,
+ 0x6c, 0x44, 0x03, 0x00, 0x01, 0xe2, 0x40, 0x09, 0x74, 0x69, 0x6d, 0x65,
+ 0x73, 0x74, 0x61, 0x6d, 0x70, 0x54, 0x00, 0x00, 0x63, 0xee, 0xa0, 0x53,
+ 0xc1, 0x94, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x00, 0x00, 0x00,
+ 0x1f, 0x03, 0x6f, 0x6e, 0x65, 0x49, 0x00, 0x00, 0xd4, 0x31, 0x03, 0x74,
+ 0x77, 0x6f, 0x53, 0x00, 0x00, 0x00, 0x0d, 0x41, 0x20, 0x6c, 0x6f, 0x6e,
+ 0x67, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x04, 0x62, 0x79, 0x74,
+ 0x65, 0x62, 0xff, 0x04, 0x6c, 0x6f, 0x6e, 0x67, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x49, 0x96, 0x02, 0xd2, 0x05, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x73,
+ 0x02, 0x8f, 0x04, 0x62, 0x6f, 0x6f, 0x6c, 0x74, 0x01, 0x06, 0x62, 0x69,
+ 0x6e, 0x61, 0x72, 0x79, 0x78, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x20, 0x62,
+ 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+ 0x04, 0x76, 0x6f, 0x69, 0x64, 0x56, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79,
+ 0x41, 0x00, 0x00, 0x00, 0x17, 0x49, 0x00, 0x00, 0xd4, 0x31, 0x53, 0x00,
+ 0x00, 0x00, 0x0d, 0x41, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x74,
+ 0x72, 0x69, 0x6e, 0x67, 0x05, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x66, 0x40,
+ 0x49, 0x0f, 0xdb, 0x06, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x64, 0x40,
+ 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18};
+
+static void test_table_codec(FILE *out) {
+ amqp_pool_t pool;
+ int result;
+
+ amqp_table_entry_t inner_entries[2];
+ amqp_table_t inner_table;
+
+ amqp_field_value_t inner_values[2];
+ amqp_array_t inner_array;
+
+ amqp_table_entry_t entries[14];
+ amqp_table_t table;
+
+ inner_entries[0].key = amqp_cstring_bytes("one");
+ inner_entries[0].value.kind = AMQP_FIELD_KIND_I32;
+ inner_entries[0].value.value.i32 = 54321;
+
+ inner_entries[1].key = amqp_cstring_bytes("two");
+ inner_entries[1].value.kind = AMQP_FIELD_KIND_UTF8;
+ inner_entries[1].value.value.bytes = amqp_cstring_bytes("A long string");
+
+ inner_table.num_entries = 2;
+ inner_table.entries = inner_entries;
+
+ inner_values[0].kind = AMQP_FIELD_KIND_I32;
+ inner_values[0].value.i32 = 54321;
+
+ inner_values[1].kind = AMQP_FIELD_KIND_UTF8;
+ inner_values[1].value.bytes = amqp_cstring_bytes("A long string");
+
+ inner_array.num_entries = 2;
+ inner_array.entries = inner_values;
+
+ entries[0].key = amqp_cstring_bytes("longstr");
+ entries[0].value.kind = AMQP_FIELD_KIND_UTF8;
+ entries[0].value.value.bytes = amqp_cstring_bytes("Here is a long string");
+
+ entries[1].key = amqp_cstring_bytes("signedint");
+ entries[1].value.kind = AMQP_FIELD_KIND_I32;
+ entries[1].value.value.i32 = 12345;
+
+ entries[2].key = amqp_cstring_bytes("decimal");
+ entries[2].value.kind = AMQP_FIELD_KIND_DECIMAL;
+ entries[2].value.value.decimal.decimals = 3;
+ entries[2].value.value.decimal.value = 123456;
+
+ entries[3].key = amqp_cstring_bytes("timestamp");
+ entries[3].value.kind = AMQP_FIELD_KIND_TIMESTAMP;
+ entries[3].value.value.u64 = 109876543209876;
+
+ entries[4].key = amqp_cstring_bytes("table");
+ entries[4].value.kind = AMQP_FIELD_KIND_TABLE;
+ entries[4].value.value.table = inner_table;
+
+ entries[5].key = amqp_cstring_bytes("byte");
+ entries[5].value.kind = AMQP_FIELD_KIND_I8;
+ entries[5].value.value.i8 = (int8_t)-1;
+
+ entries[6].key = amqp_cstring_bytes("long");
+ entries[6].value.kind = AMQP_FIELD_KIND_I64;
+ entries[6].value.value.i64 = 1234567890;
+
+ entries[7].key = amqp_cstring_bytes("short");
+ entries[7].value.kind = AMQP_FIELD_KIND_I16;
+ entries[7].value.value.i16 = 655;
+
+ entries[8].key = amqp_cstring_bytes("bool");
+ entries[8].value.kind = AMQP_FIELD_KIND_BOOLEAN;
+ entries[8].value.value.boolean = 1;
+
+ entries[9].key = amqp_cstring_bytes("binary");
+ entries[9].value.kind = AMQP_FIELD_KIND_BYTES;
+ entries[9].value.value.bytes = amqp_cstring_bytes("a binary string");
+
+ entries[10].key = amqp_cstring_bytes("void");
+ entries[10].value.kind = AMQP_FIELD_KIND_VOID;
+
+ entries[11].key = amqp_cstring_bytes("array");
+ entries[11].value.kind = AMQP_FIELD_KIND_ARRAY;
+ entries[11].value.value.array = inner_array;
+
+ entries[12].key = amqp_cstring_bytes("float");
+ entries[12].value.kind = AMQP_FIELD_KIND_F32;
+ entries[12].value.value.f32 = (float)M_PI;
+
+ entries[13].key = amqp_cstring_bytes("double");
+ entries[13].value.kind = AMQP_FIELD_KIND_F64;
+ entries[13].value.value.f64 = M_PI;
+
+ table.num_entries = 14;
+ table.entries = entries;
+
+ fprintf(out, "AAAAAAAAAA\n");
+
+ {
+ amqp_field_value_t val;
+ val.kind = AMQP_FIELD_KIND_TABLE;
+ val.value.table = table;
+ dump_value(0, val, out);
+ }
+
+ init_amqp_pool(&pool, 4096);
+
+ {
+ amqp_table_t decoded;
+ size_t decoding_offset = 0;
+ amqp_bytes_t decoding_bytes;
+ decoding_bytes.len = sizeof(pre_encoded_table);
+ decoding_bytes.bytes = pre_encoded_table;
+
+ result =
+ amqp_decode_table(decoding_bytes, &pool, &decoded, &decoding_offset);
+ if (result < 0) {
+ die("Table decoding failed: %s", amqp_error_string2(result));
+ }
+
+ fprintf(out, "BBBBBBBBBB\n");
+
+ {
+ amqp_field_value_t val;
+ val.kind = AMQP_FIELD_KIND_TABLE;
+ val.value.table = decoded;
+
+ dump_value(0, val, out);
+ }
+ }
+
+ {
+ uint8_t encoding_buffer[4096];
+ amqp_bytes_t encoding_result;
+ size_t offset = 0;
+
+ memset(&encoding_buffer[0], 0, sizeof(encoding_buffer));
+ encoding_result.len = sizeof(encoding_buffer);
+ encoding_result.bytes = &encoding_buffer[0];
+
+ result = amqp_encode_table(encoding_result, &table, &offset);
+ if (result < 0) {
+ die("Table encoding failed: %s", amqp_error_string2(result));
+ }
+
+ if (offset != sizeof(pre_encoded_table))
+ die("Offset should be %ld, was %ld", (long)sizeof(pre_encoded_table),
+ (long)offset);
+
+ result = memcmp(pre_encoded_table, encoding_buffer, offset);
+ if (result != 0) {
+ die("Table encoding differed", result);
+ }
+ }
+
+ empty_amqp_pool(&pool);
+}
+
+#define CHUNK_SIZE 4096
+
+static int compare_files(FILE *f1_in, FILE *f2_in) {
+ char f1_buf[CHUNK_SIZE];
+ char f2_buf[CHUNK_SIZE];
+ int res;
+
+ rewind(f1_in);
+ rewind(f2_in);
+
+ for (;;) {
+ size_t f1_got = fread(f1_buf, 1, CHUNK_SIZE, f1_in);
+ size_t f2_got = fread(f2_buf, 1, CHUNK_SIZE, f2_in);
+ res = memcmp(f1_buf, f2_buf, f1_got < f2_got ? f1_got : f2_got);
+
+ if (res) {
+ break;
+ }
+
+ if (f1_got < CHUNK_SIZE || f2_got < CHUNK_SIZE) {
+ if (f1_got != f2_got) {
+ res = (f1_got < f2_got ? -1 : 1);
+ }
+ break;
+ }
+ }
+
+ return res;
+}
+
+const char *expected_file_name = "tests/test_tables.expected";
+
+int main(void) {
+ char *srcdir = getenv("srcdir");
+ FILE *out, *expected = NULL;
+ char *expected_path;
+
+ out = tmpfile();
+ if (out == NULL) {
+ die("failed to create temporary file: %s", strerror(errno));
+ }
+
+ test_table_codec(out);
+ fprintf(out, "----------\n");
+ test_dump_value(out);
+
+ if (srcdir == NULL) {
+ srcdir = ".";
+ }
+
+ expected_path = malloc(strlen(srcdir) + strlen(expected_file_name) + 2);
+ if (!expected_path) {
+ die("out of memory");
+ }
+ sprintf(expected_path, "%s/%s", srcdir, expected_file_name);
+ expected = fopen(expected_path, "r");
+ if (!expected) {
+ die("failed to open %s: %s", expected_path, strerror(errno));
+ }
+
+ if (compare_files(expected, out)) {
+ die("output file did not have expected contents");
+ }
+
+ fclose(expected);
+ free(expected_path);
+ fclose(out);
+
+ return 0;
+}
diff --git a/ext/librabbitmq/tests/test_tables.expected b/ext/librabbitmq/tests/test_tables.expected
new file mode 100644
index 000000000..44d208528
--- /dev/null
+++ b/ext/librabbitmq/tests/test_tables.expected
@@ -0,0 +1,90 @@
+AAAAAAAAAA
+F
+ longstr ->
+ S Here is a long string
+ signedint ->
+ I 12345
+ decimal ->
+ D 3:::123456
+ timestamp ->
+ T 109876543209876
+ table ->
+ F
+ one ->
+ I 54321
+ two ->
+ S A long string
+ byte ->
+ b -1
+ long ->
+ l 1234567890
+ short ->
+ s 655
+ bool ->
+ t true
+ binary ->
+ x 612062696e61727920737472696e67
+ void ->
+ V
+ array ->
+ A
+ I 54321
+ S A long string
+ float ->
+ f 3.14159
+ double ->
+ d 3.14159
+BBBBBBBBBB
+F
+ longstr ->
+ S Here is a long string
+ signedint ->
+ I 12345
+ decimal ->
+ D 3:::123456
+ timestamp ->
+ T 109876543209876
+ table ->
+ F
+ one ->
+ I 54321
+ two ->
+ S A long string
+ byte ->
+ b -1
+ long ->
+ l 1234567890
+ short ->
+ s 655
+ bool ->
+ t true
+ binary ->
+ x 612062696e61727920737472696e67
+ void ->
+ V
+ array ->
+ A
+ I 54321
+ S A long string
+ float ->
+ f 3.14159
+ double ->
+ d 3.14159
+----------
+F
+ aardvark ->
+ S first
+ beta ->
+ S second
+ decimal ->
+ D 2:::1234
+ middle ->
+ S third
+ number ->
+ I 1234
+ time ->
+ T 1234123412341234
+ wombat ->
+ S fourth
+ zebra ->
+ S last
diff --git a/ext/librabbitmq/tests/win32/msinttypes/inttypes.h b/ext/librabbitmq/tests/win32/msinttypes/inttypes.h
new file mode 100644
index 000000000..f437cf45a
--- /dev/null
+++ b/ext/librabbitmq/tests/win32/msinttypes/inttypes.h
@@ -0,0 +1,304 @@
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+ intmax_t quot;
+ intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || \
+ defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64 // [
+#define SCNdPTR "I64d"
+#define SCNiPTR "I64i"
+#else // _WIN64 ][
+#define SCNdPTR "ld"
+#define SCNiPTR "li"
+#endif // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64 // [
+#define SCNoPTR "I64o"
+#define SCNuPTR "I64u"
+#define SCNxPTR "I64x"
+#define SCNXPTR "I64X"
+#else // _WIN64 ][
+#define SCNoPTR "lo"
+#define SCNuPTR "lu"
+#define SCNxPTR "lx"
+#define SCNXPTR "lX"
+#endif // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+ imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) {
+ imaxdiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ // did division wrong; must fix up
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/ext/librabbitmq/tools/CMakeLists.txt b/ext/librabbitmq/tools/CMakeLists.txt
new file mode 100644
index 000000000..1471043c4
--- /dev/null
+++ b/ext/librabbitmq/tools/CMakeLists.txt
@@ -0,0 +1,82 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${LIBRABBITMQ_INCLUDE_DIRS} ${POPT_INCLUDE_DIR})
+
+if (WIN32)
+ set(PLATFORM_DIR win32)
+ set(PLATFORM_SRCS
+ win32/compat.c
+ )
+else (WIN32)
+ set(PLATFORM_DIR unix)
+endif (WIN32)
+
+include_directories(${PLATFORM_DIR})
+
+set(COMMON_SRCS
+ common.h
+ common.c
+ ${PLATFORM_SRCS}
+ )
+
+add_executable(amqp-publish publish.c ${COMMON_SRCS})
+target_link_libraries(amqp-publish ${RMQ_LIBRARY_TARGET} ${POPT_LIBRARY})
+
+add_executable(amqp-get get.c ${COMMON_SRCS})
+target_link_libraries(amqp-get ${RMQ_LIBRARY_TARGET} ${POPT_LIBRARY})
+
+add_executable(amqp-consume consume.c ${PLATFORM_DIR}/process.c ${COMMON_SRCS})
+target_link_libraries(amqp-consume ${RMQ_LIBRARY_TARGET} ${POPT_LIBRARY})
+
+add_executable(amqp-declare-queue declare_queue.c ${COMMON_SRCS})
+target_link_libraries(amqp-declare-queue ${RMQ_LIBRARY_TARGET} ${POPT_LIBRARY})
+
+add_executable(amqp-delete-queue delete_queue.c ${COMMON_SRCS})
+target_link_libraries(amqp-delete-queue ${RMQ_LIBRARY_TARGET} ${POPT_LIBRARY})
+
+if (BUILD_TOOLS_DOCS)
+ if (XMLTO_FOUND)
+ set(DOCS_SRCS
+ doc/amqp-consume.xml
+ doc/amqp-declare-queue.xml
+ doc/amqp-delete-queue.xml
+ doc/amqp-get.xml
+ doc/amqp-publish.xml
+ doc/librabbitmq-tools.xml
+ )
+
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc)
+ set(XMLTO_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/doc/man-date.ent)
+ add_custom_command(
+ OUTPUT ${XMLTO_DEPENDS}
+ COMMAND date +'%Y-%m-%d' > ${XMLTO_DEPENDS}
+ VERBATIM
+ )
+
+ set(XMLTO_COMMAND_ARGS --skip-validation --searchpath "${CMAKE_CURRENT_BINARY_DIR}/doc")
+
+ XMLTO(${DOCS_SRCS}
+ MODES man
+ ALL)
+
+ foreach(file ${XMLTO_FILES_man})
+ get_filename_component(fileExt ${file} EXT)
+ string( REGEX REPLACE "^[.]" "" fileExt ${fileExt} )
+ install(
+ FILES ${file}
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man${fileExt}
+ )
+ endforeach()
+
+ else(XMLTO_FOUND)
+ message(WARNING "xmlto not found, will not build tools documentation")
+ endif(XMLTO_FOUND)
+endif()
+
+if (ENABLE_SSL_SUPPORT)
+ add_definitions(-DWITH_SSL=1)
+endif()
+
+install(TARGETS amqp-publish amqp-get amqp-consume amqp-declare-queue amqp-delete-queue
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+ PUBLIC_HEADER DESTINATION include)
diff --git a/ext/librabbitmq/tools/common.c b/ext/librabbitmq/tools/common.c
new file mode 100644
index 000000000..13839a881
--- /dev/null
+++ b/ext/librabbitmq/tools/common.c
@@ -0,0 +1,444 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MIT
+ *
+ * Portions created by Alan Antonuk are Copyright (c) 2012-2013
+ * Alan Antonuk. All Rights Reserved.
+ *
+ * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
+ * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "common.h"
+#ifdef WITH_SSL
+#include
+#endif
+#include
+#include
+#include
+#include