mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-20 14:06:54 +02:00
Merge branch 'edge' of http://git.int.zerotier.com/zerotier/ZeroTierOne into edge
This commit is contained in:
commit
0f4fc8635b
120 changed files with 19903 additions and 50 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -120,3 +120,4 @@ __pycache__
|
|||
*~
|
||||
attic/world/*.c25519
|
||||
attic/world/mkworld
|
||||
/version.h
|
||||
|
|
131
CMakeLists.txt
131
CMakeLists.txt
|
@ -1,12 +1,127 @@
|
|||
# CMake build script for libzerotiercore.a
|
||||
# CMake build script for ZeroTier One
|
||||
|
||||
cmake_minimum_required (VERSION 2.8)
|
||||
project (zerotiercore)
|
||||
cmake_minimum_required (VERSION 3.8)
|
||||
|
||||
set (PROJ_DIR ${PROJECT_SOURCE_DIR})
|
||||
set (ZT_DEFS -std=c++11)
|
||||
# ZeroTier One Version Config
|
||||
|
||||
file(GLOB core_src_glob ${PROJ_DIR}/node/*.cpp)
|
||||
add_library(zerotiercore STATIC ${core_src_glob})
|
||||
set(ZEROTIER_ONE_VERSION_MAJOR 1)
|
||||
set(ZEROTIER_ONE_VERSION_MINOR 4)
|
||||
set(ZEROTIER_ONE_VERSION_REVISION 2)
|
||||
set(ZEROTIER_ONE_VERSION_BUILD 0)
|
||||
|
||||
target_compile_options(zerotiercore PRIVATE ${ZT_DEFS})
|
||||
# Set a default build type if none was specified
|
||||
set(default_build_type "Release")
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
set(default_build_type "Debug")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE
|
||||
STRING "Choose the type of build." FORCE)
|
||||
# Set the possible values of build type for cmake-gui
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
option(BUILD_CENTRAL_CONTROLLER "Build ZeroTier Central Controller" OFF)
|
||||
|
||||
if (BUILD_CENTRAL_CONTROLLER)
|
||||
find_package(PostgreSQL REQUIRED)
|
||||
|
||||
set(ENABLE_SSL_SUPPORT OFF)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
set(BUILD_EXAMPLES OFF)
|
||||
set(BUILD_TOOLS OFF)
|
||||
set(BUILD_TESTS OFF)
|
||||
set(BUILD_API_DOCS OFF)
|
||||
add_subdirectory("ext/librabbitmq")
|
||||
endif(BUILD_CENTRAL_CONTROLLER)
|
||||
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X Deployment Version")
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DZT_TRACE)
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DNOMINMAX)
|
||||
else(WIN32)
|
||||
if(APPLE)
|
||||
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
message("Setting Linux Compiler Flags ${CMAKE_BUILD_TYPE}")
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wno-deprecated
|
||||
$<$<CONFIG:Debug>:-g>
|
||||
$<$<CONFIG:DEBUG>:-O0>
|
||||
$<$<CONFIG:RELEASE>:-O3>
|
||||
$<$<CONFIG:RELEASE>:-fstackprotector>
|
||||
$<$<CONFIG:RELEASE>:-fPIE>
|
||||
$<$<CONFIG:RELWITHDEBINFO>:-O3>
|
||||
$<$<CONFIG:RELWITHDEBINFO>:-fstackprotector>
|
||||
$<$<CONFIG:RELWITHDEBINFO>:-fPIE>
|
||||
$<$<CONFIG:RELWITHDEBINFO>:-g>
|
||||
)
|
||||
endif(APPLE)
|
||||
endif(WIN32)
|
||||
|
||||
project(zerotier-one)
|
||||
|
||||
add_subdirectory(node)
|
||||
add_subdirectory(controller)
|
||||
add_subdirectory(osdep)
|
||||
add_subdirectory(service)
|
||||
|
||||
if(WIN32)
|
||||
add_subdirectory("windows/WinUI")
|
||||
add_subdirectory("windows/copyutil")
|
||||
add_definitions(-DNOMINMAX)
|
||||
endif(WIN32)
|
||||
|
||||
set(libs
|
||||
zt_service
|
||||
zt_osdep
|
||||
zt_core
|
||||
zt_controller
|
||||
)
|
||||
|
||||
configure_file(
|
||||
version.h.in
|
||||
${CMAKE_SOURCE_DIR}/version.h
|
||||
)
|
||||
|
||||
set(src
|
||||
one.cpp
|
||||
"ext/http-parser/http_parser.c"
|
||||
)
|
||||
set(headers
|
||||
"ext/http-parser/http_parser.h"
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi)
|
||||
set(src
|
||||
${src}
|
||||
"windows/ZeroTierOne/ServiceBase.cpp"
|
||||
"windows/ZeroTierOne/ServiceInstaller.cpp"
|
||||
"windows/ZeroTierOne/ZeroTierOneService.cpp"
|
||||
"windows/ZeroTierOne/ZeroTierOne.rc"
|
||||
)
|
||||
set(headers
|
||||
${headers}
|
||||
"windows/ZeroTierOne/ServiceBase.h"
|
||||
"windows/ZeroTierOne/ServiceInstaller.h"
|
||||
"windows/ZeroTierOne/ZeroTierOneService.h"
|
||||
)
|
||||
else(WIN32)
|
||||
set(libs ${libs} pthread)
|
||||
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})
|
||||
|
|
6
Jenkinsfile
vendored
6
Jenkinsfile
vendored
|
@ -14,7 +14,11 @@ parallel 'centos7': {
|
|||
checkout scm
|
||||
|
||||
stage('Build Centos 7') {
|
||||
sh 'make -f make-linux.mk'
|
||||
sh '''rm -rf build/
|
||||
mkdir build && cd build
|
||||
CC=clang CXX=clang++ cmake ..
|
||||
make -j4
|
||||
'''
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
|
|
36
controller/CMakeLists.txt
Normal file
36
controller/CMakeLists.txt
Normal file
|
@ -0,0 +1,36 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
project(zt_controller)
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DNOMINMAX)
|
||||
endif(WIN32)
|
||||
|
||||
set(ctl_src
|
||||
DB.cpp
|
||||
DBMirrorSet.cpp
|
||||
EmbeddedNetworkController.cpp
|
||||
FileDB.cpp
|
||||
LFDB.cpp
|
||||
RabbitMQ.cpp
|
||||
)
|
||||
|
||||
set(ctl_hdr
|
||||
DB.hpp
|
||||
DBMirrorSet.hpp
|
||||
EmbeddedNetworkController.hpp
|
||||
FileDB.hpp
|
||||
LFDB.hpp
|
||||
RabbitMQ.hpp
|
||||
)
|
||||
|
||||
if(BUILD_CENTRAL_CONTROLLER)
|
||||
add_definitions(-DZT_CONTROLLER_USE_LIBPQ)
|
||||
include_directories("../ext/librabbitmq/librabbitmq" ${PostgreSQL_INCLUDE_DIRS})
|
||||
|
||||
set(ctl_src ${ctl_src} PostgreSQL.cpp)
|
||||
set(ctl_hdr ${ctl_hdr} PostgreSQL.hpp)
|
||||
endif(BUILD_CENTRAL_CONTROLLER)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${ctl_src} ${ctl_hdr})
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)
|
||||
|
47
ext/librabbitmq/.clang-format
Normal file
47
ext/librabbitmq/.clang-format
Normal file
|
@ -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
|
||||
...
|
||||
|
18
ext/librabbitmq/.gitattributes
vendored
Normal file
18
ext/librabbitmq/.gitattributes
vendored
Normal file
|
@ -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
|
||||
|
73
ext/librabbitmq/.gitignore
vendored
Normal file
73
ext/librabbitmq/.gitignore
vendored
Normal file
|
@ -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?
|
||||
.#*
|
||||
\#*#
|
6
ext/librabbitmq/.gitmodules
vendored
Normal file
6
ext/librabbitmq/.gitmodules
vendored
Normal file
|
@ -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
|
92
ext/librabbitmq/.travis.yml
Normal file
92
ext/librabbitmq/.travis.yml
Normal file
|
@ -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
|
157
ext/librabbitmq/.ycm_extra_conf.py
Normal file
157
ext/librabbitmq/.ycm_extra_conf.py
Normal file
|
@ -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 <http://unlicense.org/>
|
||||
|
||||
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=<something>" 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=<something>".
|
||||
# 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
|
||||
}
|
2
ext/librabbitmq/AUTHORS
Normal file
2
ext/librabbitmq/AUTHORS
Normal file
|
@ -0,0 +1,2 @@
|
|||
Tony Garnock-Jones <tonygarnockjones@gmail.com>
|
||||
The RabbitMQ team <info@rabbitmq.com>
|
343
ext/librabbitmq/CMakeLists.txt
Normal file
343
ext/librabbitmq/CMakeLists.txt
Normal file
|
@ -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 ()
|
26
ext/librabbitmq/CONTRIBUTING.md
Normal file
26
ext/librabbitmq/CONTRIBUTING.md
Normal file
|
@ -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
|
||||
|
221
ext/librabbitmq/ChangeLog.md
Normal file
221
ext/librabbitmq/ChangeLog.md
Normal file
|
@ -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
|
28
ext/librabbitmq/LICENSE-MIT
Normal file
28
ext/librabbitmq/LICENSE-MIT
Normal file
|
@ -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.
|
128
ext/librabbitmq/README.md
Normal file
128
ext/librabbitmq/README.md
Normal file
|
@ -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.
|
||||
|
||||
- <http://github.com/alanxz/rabbitmq-c>
|
||||
|
||||
Announcements regarding the library are periodically made on the
|
||||
rabbitmq-c-users and cross-posted to rabbitmq-users.
|
||||
|
||||
- <https://groups.google.com/forum/#!forum/rabbitmq-c-users>
|
||||
- <https://groups.google.com/forum/#!forum/rabbitmq-users>
|
||||
|
||||
## Latest Stable Version
|
||||
|
||||
The latest stable release of rabbitmq-c can be found at:
|
||||
|
||||
- <https://github.com/alanxz/rabbitmq-c/releases/latest>
|
||||
|
||||
## Documentation
|
||||
|
||||
API documentation for v0.8.0+ can viewed from:
|
||||
|
||||
<http://alanxz.github.io/rabbitmq-c/docs/0.8.0/>
|
||||
|
||||
## 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.
|
8
ext/librabbitmq/THANKS
Normal file
8
ext/librabbitmq/THANKS
Normal file
|
@ -0,0 +1,8 @@
|
|||
Thank-you to the following people for their contributions to the
|
||||
codebase:
|
||||
|
||||
- Scott Brooks / Epic Advertising <scott.brooks@epicadvertising.com>
|
||||
|
||||
- Frank Gönninger <frank.goenninger@consequor.de>
|
||||
|
||||
- Daniel Schauenberg <d@unwiredcouch.com>
|
9
ext/librabbitmq/TODO
Normal file
9
ext/librabbitmq/TODO
Normal file
|
@ -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.
|
34
ext/librabbitmq/appveyor.yml
Normal file
34
ext/librabbitmq/appveyor.yml
Normal file
|
@ -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
|
Binary file not shown.
103
ext/librabbitmq/cmake/CMakePushCheckState.cmake
Normal file
103
ext/librabbitmq/cmake/CMakePushCheckState.cmake
Normal file
|
@ -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, <neundorf@kde.org>
|
||||
#
|
||||
# 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()
|
22
ext/librabbitmq/cmake/COPYING-CMAKE-SCRIPTS
Normal file
22
ext/librabbitmq/cmake/COPYING-CMAKE-SCRIPTS
Normal file
|
@ -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.
|
39
ext/librabbitmq/cmake/FindPOPT.cmake
Normal file
39
ext/librabbitmq/cmake/FindPOPT.cmake
Normal file
|
@ -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)
|
98
ext/librabbitmq/cmake/FindXmlTo.cmake
Normal file
98
ext/librabbitmq/cmake/FindXmlTo.cmake
Normal file
|
@ -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 <manvolnum>
|
||||
if ( "${mode}" STREQUAL "man" )
|
||||
file ( READ "${dbFile}" _DB_FILE_CONTENTS )
|
||||
string ( REGEX MATCH "<manvolnum>[^<]*" XMLTO_FILEEXT_${mode} "${_DB_FILE_CONTENTS}" )
|
||||
string ( REGEX REPLACE "^<manvolnum>" "" 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 )
|
205
ext/librabbitmq/cmake/GNUInstallDirs.cmake
Normal file
205
ext/librabbitmq/cmake/GNUInstallDirs.cmake
Normal file
|
@ -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_<dir> - destination for files of a given type
|
||||
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
|
||||
#
|
||||
# where <dir> 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/<multiarch-tuple> 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_<dir> 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_<dir> 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 <krnekit@gmail.com>
|
||||
# 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()
|
28
ext/librabbitmq/cmake/TestCInline.cmake
Normal file
28
ext/librabbitmq/cmake/TestCInline.cmake
Normal file
|
@ -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)
|
14
ext/librabbitmq/cmake/config.h.in
Normal file
14
ext/librabbitmq/cmake/config.h.in
Normal file
|
@ -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 */
|
17
ext/librabbitmq/coverity/model.c
Normal file
17
ext/librabbitmq/coverity/model.c
Normal file
|
@ -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__(); }
|
317
ext/librabbitmq/docs/Doxyfile.in
Normal file
317
ext/librabbitmq/docs/Doxyfile.in
Normal file
|
@ -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
|
52
ext/librabbitmq/examples/CMakeLists.txt
Normal file
52
ext/librabbitmq/examples/CMakeLists.txt
Normal file
|
@ -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)
|
95
ext/librabbitmq/examples/amqp_bind.c
Normal file
95
ext/librabbitmq/examples/amqp_bind.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#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;
|
||||
}
|
114
ext/librabbitmq/examples/amqp_connect_timeout.c
Normal file
114
ext/librabbitmq/examples/amqp_connect_timeout.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#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;
|
||||
}
|
215
ext/librabbitmq/examples/amqp_consumer.c
Normal file
215
ext/librabbitmq/examples/amqp_consumer.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#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;
|
||||
}
|
94
ext/librabbitmq/examples/amqp_exchange_declare.c
Normal file
94
ext/librabbitmq/examples/amqp_exchange_declare.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#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;
|
||||
}
|
143
ext/librabbitmq/examples/amqp_listen.c
Normal file
143
ext/librabbitmq/examples/amqp_listen.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#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;
|
||||
}
|
122
ext/librabbitmq/examples/amqp_listenq.c
Normal file
122
ext/librabbitmq/examples/amqp_listenq.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#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;
|
||||
}
|
150
ext/librabbitmq/examples/amqp_producer.c
Normal file
150
ext/librabbitmq/examples/amqp_producer.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#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;
|
||||
}
|
243
ext/librabbitmq/examples/amqp_rpc_sendstring_client.c
Normal file
243
ext/librabbitmq/examples/amqp_rpc_sendstring_client.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#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;
|
||||
}
|
103
ext/librabbitmq/examples/amqp_sendstring.c
Normal file
103
ext/librabbitmq/examples/amqp_sendstring.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#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;
|
||||
}
|
135
ext/librabbitmq/examples/amqp_ssl_connect.c
Normal file
135
ext/librabbitmq/examples/amqp_ssl_connect.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_ssl_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#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;
|
||||
}
|
95
ext/librabbitmq/examples/amqp_unbind.c
Normal file
95
ext/librabbitmq/examples/amqp_unbind.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#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;
|
||||
}
|
52
ext/librabbitmq/examples/unix/platform_utils.c
Normal file
52
ext/librabbitmq/examples/unix/platform_utils.c
Normal file
|
@ -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 <stdint.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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);
|
||||
}
|
188
ext/librabbitmq/examples/utils.c
Normal file
188
ext/librabbitmq/examples/utils.c
Normal file
|
@ -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 <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_framing.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
48
ext/librabbitmq/examples/utils.h
Normal file
48
ext/librabbitmq/examples/utils.h
Normal file
|
@ -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
|
47
ext/librabbitmq/examples/win32/platform_utils.c
Normal file
47
ext/librabbitmq/examples/win32/platform_utils.c
Normal file
|
@ -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 <stdint.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
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); }
|
13
ext/librabbitmq/librabbitmq.pc.in
Normal file
13
ext/librabbitmq/librabbitmq.pc.in
Normal file
|
@ -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}
|
186
ext/librabbitmq/librabbitmq/CMakeLists.txt
Normal file
186
ext/librabbitmq/librabbitmq/CMakeLists.txt
Normal file
|
@ -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)
|
|
@ -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
|
394
ext/librabbitmq/librabbitmq/amqp_api.c
Normal file
394
ext/librabbitmq/librabbitmq/amqp_api.c
Normal file
|
@ -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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
595
ext/librabbitmq/librabbitmq/amqp_connection.c
Normal file
595
ext/librabbitmq/librabbitmq/amqp_connection.c
Normal file
|
@ -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 <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
307
ext/librabbitmq/librabbitmq/amqp_consumer.c
Normal file
307
ext/librabbitmq/librabbitmq/amqp_consumer.c
Normal file
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
2876
ext/librabbitmq/librabbitmq/amqp_framing.c
Normal file
2876
ext/librabbitmq/librabbitmq/amqp_framing.c
Normal file
File diff suppressed because it is too large
Load diff
195
ext/librabbitmq/librabbitmq/amqp_hostcheck.c
Normal file
195
ext/librabbitmq/librabbitmq/amqp_hostcheck.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright 1996-2014 Daniel Stenberg <daniel@haxx.se>.
|
||||
* 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 <string.h>
|
||||
|
||||
/* 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);
|
||||
}
|
48
ext/librabbitmq/librabbitmq/amqp_hostcheck.h
Normal file
48
ext/librabbitmq/librabbitmq/amqp_hostcheck.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef librabbitmq_amqp_hostcheck_h
|
||||
#define librabbitmq_amqp_hostcheck_h
|
||||
|
||||
/*
|
||||
* Copyright 1996-2014 Daniel Stenberg <daniel@haxx.se>.
|
||||
* 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
|
242
ext/librabbitmq/librabbitmq/amqp_mem.c
Normal file
242
ext/librabbitmq/librabbitmq/amqp_mem.c
Normal file
|
@ -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 <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
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;
|
||||
}
|
704
ext/librabbitmq/librabbitmq/amqp_openssl.c
Normal file
704
ext/librabbitmq/librabbitmq/amqp_openssl.c
Normal file
|
@ -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 <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/engine.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
193
ext/librabbitmq/librabbitmq/amqp_openssl_bio.c
Normal file
193
ext/librabbitmq/librabbitmq/amqp_openssl_bio.c
Normal file
|
@ -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 <assert.h>
|
||||
#include <errno.h>
|
||||
#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#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
|
||||
}
|
44
ext/librabbitmq/librabbitmq/amqp_openssl_bio.h
Normal file
44
ext/librabbitmq/librabbitmq/amqp_openssl_bio.h
Normal file
|
@ -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 <openssl/bio.h>
|
||||
|
||||
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 */
|
179
ext/librabbitmq/librabbitmq/amqp_openssl_hostname_validation.c
Normal file
179
ext/librabbitmq/librabbitmq/amqp_openssl_hostname_validation.c
Normal file
|
@ -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 <openssl/ssl.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#include "amqp_hostcheck.h"
|
||||
#include "amqp_openssl_bio.h"
|
||||
#include "amqp_openssl_hostname_validation.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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 <openssl/x509v3.h>
|
||||
|
||||
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
|
374
ext/librabbitmq/librabbitmq/amqp_private.h
Normal file
374
ext/librabbitmq/librabbitmq/amqp_private.h
Normal file
|
@ -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 <string.h>
|
||||
|
||||
#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 <winsock2.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/uio.h>
|
||||
#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
|
1492
ext/librabbitmq/librabbitmq/amqp_socket.c
Normal file
1492
ext/librabbitmq/librabbitmq/amqp_socket.c
Normal file
File diff suppressed because it is too large
Load diff
188
ext/librabbitmq/librabbitmq/amqp_socket.h
Normal file
188
ext/librabbitmq/librabbitmq/amqp_socket.h
Normal file
|
@ -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 */
|
239
ext/librabbitmq/librabbitmq/amqp_ssl_socket.h
Normal file
239
ext/librabbitmq/librabbitmq/amqp_ssl_socket.h
Normal file
|
@ -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.h>
|
||||
|
||||
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 */
|
668
ext/librabbitmq/librabbitmq/amqp_table.c
Normal file
668
ext/librabbitmq/librabbitmq/amqp_table.c
Normal file
|
@ -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 <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
81
ext/librabbitmq/librabbitmq/amqp_table.h
Normal file
81
ext/librabbitmq/librabbitmq/amqp_table.h
Normal file
|
@ -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 */
|
238
ext/librabbitmq/librabbitmq/amqp_tcp_socket.c
Normal file
238
ext/librabbitmq/librabbitmq/amqp_tcp_socket.c
Normal file
|
@ -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 <errno.h>
|
||||
#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
265
ext/librabbitmq/librabbitmq/amqp_time.c
Normal file
265
ext/librabbitmq/librabbitmq/amqp_time.c
Normal file
|
@ -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 <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 <windows.h>
|
||||
|
||||
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 <mach/mach_time.h>
|
||||
|
||||
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 <time.h>
|
||||
|
||||
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;
|
||||
}
|
130
ext/librabbitmq/librabbitmq/amqp_time.h
Normal file
130
ext/librabbitmq/librabbitmq/amqp_time.h
Normal file
|
@ -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 <stdint.h>
|
||||
|
||||
#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 <winsock2.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#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 */
|
220
ext/librabbitmq/librabbitmq/amqp_url.c
Normal file
220
ext/librabbitmq/librabbitmq/amqp_url.c
Normal file
|
@ -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 <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
785
ext/librabbitmq/librabbitmq/codegen.py
Normal file
785
ext/librabbitmq/librabbitmq/codegen.py
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
"""
|
||||
|
||||
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.h>
|
||||
|
||||
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)
|
28
ext/librabbitmq/librabbitmq/unix/threads.h
Normal file
28
ext/librabbitmq/librabbitmq/unix/threads.h
Normal file
|
@ -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 <pthread.h>
|
||||
|
||||
#endif /* AMQP_THREADS_H */
|
245
ext/librabbitmq/librabbitmq/win32/msinttypes/stdint.h
Normal file
245
ext/librabbitmq/librabbitmq/win32/msinttypes/stdint.h
Normal file
|
@ -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 <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we should wrap <wchar.h> 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 <wchar.h>
|
||||
#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 <wchar.h>
|
||||
#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_ ]
|
56
ext/librabbitmq/librabbitmq/win32/threads.c
Normal file
56
ext/librabbitmq/librabbitmq/win32/threads.c
Normal file
|
@ -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 <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
52
ext/librabbitmq/librabbitmq/win32/threads.h
Normal file
52
ext/librabbitmq/librabbitmq/win32/threads.h
Normal file
|
@ -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 <windows.h>
|
||||
|
||||
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 */
|
47
ext/librabbitmq/tests/CMakeLists.txt
Normal file
47
ext/librabbitmq/tests/CMakeLists.txt
Normal file
|
@ -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)
|
||||
|
207
ext/librabbitmq/tests/test_basic.c
Normal file
207
ext/librabbitmq/tests/test_basic.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
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;
|
||||
}
|
71
ext/librabbitmq/tests/test_hostcheck.c
Normal file
71
ext/librabbitmq/tests/test_hostcheck.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
203
ext/librabbitmq/tests/test_merge_capabilities.c
Normal file
203
ext/librabbitmq/tests/test_merge_capabilities.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
220
ext/librabbitmq/tests/test_parse_url.c
Normal file
220
ext/librabbitmq/tests/test_parse_url.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <amqp.h>
|
||||
|
||||
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;
|
||||
}
|
70
ext/librabbitmq/tests/test_sasl_mechanism.c
Normal file
70
ext/librabbitmq/tests/test_sasl_mechanism.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp_socket.h>
|
||||
|
||||
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;
|
||||
}
|
52
ext/librabbitmq/tests/test_status_enum.c
Normal file
52
ext/librabbitmq/tests/test_status_enum.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
466
ext/librabbitmq/tests/test_tables.c
Normal file
466
ext/librabbitmq/tests/test_tables.c
Normal file
|
@ -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 <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <amqp.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
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;
|
||||
}
|
90
ext/librabbitmq/tests/test_tables.expected
Normal file
90
ext/librabbitmq/tests/test_tables.expected
Normal file
|
@ -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
|
304
ext/librabbitmq/tests/win32/msinttypes/inttypes.h
Normal file
304
ext/librabbitmq/tests/win32/msinttypes/inttypes.h
Normal file
|
@ -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_ ]
|
82
ext/librabbitmq/tools/CMakeLists.txt
Normal file
82
ext/librabbitmq/tools/CMakeLists.txt
Normal file
|
@ -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)
|
444
ext/librabbitmq/tools/common.c
Normal file
444
ext/librabbitmq/tools/common.c
Normal file
|
@ -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 <amqp_ssl_socket.h>
|
||||
#endif
|
||||
#include <amqp_tcp_socket.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include "compat.h"
|
||||
#endif
|
||||
|
||||
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_errno(int err, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
if (err == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, ": %s\n", strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void die_amqp_error(int err, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
if (err >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, ": %s\n", amqp_error_string2(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *amqp_server_exception_string(amqp_rpc_reply_t r) {
|
||||
int res;
|
||||
static char s[512];
|
||||
|
||||
switch (r.reply.id) {
|
||||
case AMQP_CONNECTION_CLOSE_METHOD: {
|
||||
amqp_connection_close_t *m = (amqp_connection_close_t *)r.reply.decoded;
|
||||
res = snprintf(s, sizeof(s), "server connection error %d, message: %.*s",
|
||||
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 *)r.reply.decoded;
|
||||
res = snprintf(s, sizeof(s), "server channel error %d, message: %.*s",
|
||||
m->reply_code, (int)m->reply_text.len,
|
||||
(char *)m->reply_text.bytes);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
res = snprintf(s, sizeof(s), "unknown server error, method id 0x%08X",
|
||||
r.reply.id);
|
||||
break;
|
||||
}
|
||||
|
||||
return res >= 0 ? s : NULL;
|
||||
}
|
||||
|
||||
const char *amqp_rpc_reply_string(amqp_rpc_reply_t r) {
|
||||
switch (r.reply_type) {
|
||||
case AMQP_RESPONSE_NORMAL:
|
||||
return "normal response";
|
||||
|
||||
case AMQP_RESPONSE_NONE:
|
||||
return "missing RPC reply type";
|
||||
|
||||
case AMQP_RESPONSE_LIBRARY_EXCEPTION:
|
||||
return amqp_error_string2(r.library_error);
|
||||
|
||||
case AMQP_RESPONSE_SERVER_EXCEPTION:
|
||||
return amqp_server_exception_string(r);
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void die_rpc(amqp_rpc_reply_t r, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
if (r.reply_type == AMQP_RESPONSE_NORMAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, ": %s\n", amqp_rpc_reply_string(r));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static char *amqp_url;
|
||||
static char *amqp_server;
|
||||
static int amqp_port = -1;
|
||||
static char *amqp_vhost;
|
||||
static char *amqp_username;
|
||||
static char *amqp_password;
|
||||
static int amqp_heartbeat = 0;
|
||||
#ifdef WITH_SSL
|
||||
static int amqp_ssl = 0;
|
||||
static char *amqp_cacert = "/etc/ssl/certs/cacert.pem";
|
||||
static char *amqp_key = NULL;
|
||||
static char *amqp_cert = NULL;
|
||||
#endif /* WITH_SSL */
|
||||
|
||||
const char *connect_options_title = "Connection options";
|
||||
struct poptOption connect_options[] = {
|
||||
{"url", 'u', POPT_ARG_STRING, &amqp_url, 0, "the AMQP URL to connect to",
|
||||
"amqp://..."},
|
||||
{"server", 's', POPT_ARG_STRING, &amqp_server, 0,
|
||||
"the AMQP server to connect to", "hostname"},
|
||||
{"port", 0, POPT_ARG_INT, &amqp_port, 0, "the port to connect on", "port"},
|
||||
{"vhost", 0, POPT_ARG_STRING, &amqp_vhost, 0,
|
||||
"the vhost to use when connecting", "vhost"},
|
||||
{"username", 0, POPT_ARG_STRING, &amqp_username, 0,
|
||||
"the username to login with", "username"},
|
||||
{"password", 0, POPT_ARG_STRING, &amqp_password, 0,
|
||||
"the password to login with", "password"},
|
||||
{"heartbeat", 0, POPT_ARG_INT, &amqp_heartbeat, 0,
|
||||
"heartbeat interval, set to 0 to disable", "heartbeat"},
|
||||
#ifdef WITH_SSL
|
||||
{"ssl", 0, POPT_ARG_NONE, &amqp_ssl, 0, "connect over SSL/TLS", NULL},
|
||||
{"cacert", 0, POPT_ARG_STRING, &amqp_cacert, 0,
|
||||
"path to the CA certificate file", "cacert.pem"},
|
||||
{"key", 0, POPT_ARG_STRING, &amqp_key, 0,
|
||||
"path to the client private key file", "key.pem"},
|
||||
{"cert", 0, POPT_ARG_STRING, &amqp_cert, 0,
|
||||
"path to the client certificate file", "cert.pem"},
|
||||
#endif /* WITH_SSL */
|
||||
{NULL, '\0', 0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static void init_connection_info(struct amqp_connection_info *ci) {
|
||||
ci->user = NULL;
|
||||
ci->password = NULL;
|
||||
ci->host = NULL;
|
||||
ci->port = -1;
|
||||
ci->vhost = NULL;
|
||||
ci->user = NULL;
|
||||
|
||||
amqp_default_connection_info(ci);
|
||||
|
||||
if (amqp_url)
|
||||
die_amqp_error(amqp_parse_url(strdup(amqp_url), ci), "Parsing URL '%s'",
|
||||
amqp_url);
|
||||
|
||||
if (amqp_server) {
|
||||
char *colon;
|
||||
if (amqp_url) {
|
||||
die("--server and --url options cannot be used at the same time");
|
||||
}
|
||||
|
||||
/* parse the server string into a hostname and a port */
|
||||
colon = strchr(amqp_server, ':');
|
||||
if (colon) {
|
||||
char *port_end;
|
||||
size_t host_len;
|
||||
|
||||
/* Deprecate specifying the port number with the
|
||||
--server option, because it is not ipv6 friendly.
|
||||
--url now allows connection options to be
|
||||
specified concisely. */
|
||||
fprintf(stderr,
|
||||
"Specifying the port number with --server is deprecated\n");
|
||||
|
||||
host_len = colon - amqp_server;
|
||||
ci->host = malloc(host_len + 1);
|
||||
memcpy(ci->host, amqp_server, host_len);
|
||||
ci->host[host_len] = 0;
|
||||
|
||||
if (amqp_port >= 0) {
|
||||
die("both --server and --port options specify server port");
|
||||
}
|
||||
|
||||
ci->port = strtol(colon + 1, &port_end, 10);
|
||||
if (ci->port < 0 || ci->port > 65535 || port_end == colon + 1 ||
|
||||
*port_end != 0)
|
||||
die("bad server port number in '%s'", amqp_server);
|
||||
}
|
||||
|
||||
#if WITH_SSL
|
||||
if (amqp_ssl && !ci->ssl) {
|
||||
die("the --ssl option specifies an SSL connection"
|
||||
" but the --url option does not");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (amqp_port >= 0) {
|
||||
if (amqp_url) {
|
||||
die("--port and --url options cannot be used at the same time");
|
||||
}
|
||||
|
||||
ci->port = amqp_port;
|
||||
}
|
||||
|
||||
if (amqp_username) {
|
||||
if (amqp_url) {
|
||||
die("--username and --url options cannot be used at the same time");
|
||||
}
|
||||
|
||||
ci->user = amqp_username;
|
||||
}
|
||||
|
||||
if (amqp_password) {
|
||||
if (amqp_url) {
|
||||
die("--password and --url options cannot be used at the same time");
|
||||
}
|
||||
|
||||
ci->password = amqp_password;
|
||||
}
|
||||
|
||||
if (amqp_vhost) {
|
||||
if (amqp_url) {
|
||||
die("--vhost and --url options cannot be used at the same time");
|
||||
}
|
||||
|
||||
ci->vhost = amqp_vhost;
|
||||
}
|
||||
|
||||
if (amqp_heartbeat < 0) {
|
||||
die("--heartbeat must be a positive value");
|
||||
}
|
||||
}
|
||||
|
||||
amqp_connection_state_t make_connection(void) {
|
||||
int status;
|
||||
amqp_socket_t *socket = NULL;
|
||||
struct amqp_connection_info ci;
|
||||
amqp_connection_state_t conn;
|
||||
|
||||
init_connection_info(&ci);
|
||||
conn = amqp_new_connection();
|
||||
if (ci.ssl) {
|
||||
#ifdef WITH_SSL
|
||||
socket = amqp_ssl_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating SSL/TLS socket");
|
||||
}
|
||||
if (amqp_cacert) {
|
||||
amqp_ssl_socket_set_cacert(socket, amqp_cacert);
|
||||
}
|
||||
if (amqp_key) {
|
||||
amqp_ssl_socket_set_key(socket, amqp_cert, amqp_key);
|
||||
}
|
||||
#else
|
||||
die("librabbitmq was not built with SSL/TLS support");
|
||||
#endif
|
||||
} else {
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket (out of memory)");
|
||||
}
|
||||
}
|
||||
status = amqp_socket_open(socket, ci.host, ci.port);
|
||||
if (status) {
|
||||
die("opening socket to %s:%d", ci.host, ci.port);
|
||||
}
|
||||
die_rpc(amqp_login(conn, ci.vhost, 0, 131072, amqp_heartbeat,
|
||||
AMQP_SASL_METHOD_PLAIN, ci.user, ci.password),
|
||||
"logging in to AMQP server");
|
||||
if (!amqp_channel_open(conn, 1)) {
|
||||
die_rpc(amqp_get_rpc_reply(conn), "opening channel");
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
void close_connection(amqp_connection_state_t conn) {
|
||||
int res;
|
||||
die_rpc(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS), "closing channel");
|
||||
die_rpc(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"closing connection");
|
||||
|
||||
res = amqp_destroy_connection(conn);
|
||||
die_amqp_error(res, "closing connection");
|
||||
}
|
||||
|
||||
amqp_bytes_t read_all(int fd) {
|
||||
size_t space = 4096;
|
||||
amqp_bytes_t bytes;
|
||||
|
||||
bytes.bytes = malloc(space);
|
||||
bytes.len = 0;
|
||||
|
||||
for (;;) {
|
||||
ssize_t res = read(fd, (char *)bytes.bytes + bytes.len, space - bytes.len);
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
die_errno(errno, "reading");
|
||||
}
|
||||
|
||||
bytes.len += res;
|
||||
if (bytes.len == space) {
|
||||
space *= 2;
|
||||
bytes.bytes = realloc(bytes.bytes, space);
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void write_all(int fd, amqp_bytes_t data) {
|
||||
while (data.len > 0) {
|
||||
ssize_t res = write(fd, data.bytes, data.len);
|
||||
if (res < 0) {
|
||||
die_errno(errno, "write");
|
||||
}
|
||||
|
||||
data.len -= res;
|
||||
data.bytes = (char *)data.bytes + res;
|
||||
}
|
||||
}
|
||||
|
||||
void copy_body(amqp_connection_state_t conn, int fd) {
|
||||
size_t body_remaining;
|
||||
amqp_frame_t frame;
|
||||
|
||||
int res = amqp_simple_wait_frame(conn, &frame);
|
||||
die_amqp_error(res, "waiting for header frame");
|
||||
if (frame.frame_type != AMQP_FRAME_HEADER) {
|
||||
die("expected header, got frame type 0x%X", frame.frame_type);
|
||||
}
|
||||
|
||||
body_remaining = frame.payload.properties.body_size;
|
||||
while (body_remaining) {
|
||||
res = amqp_simple_wait_frame(conn, &frame);
|
||||
die_amqp_error(res, "waiting for body frame");
|
||||
if (frame.frame_type != AMQP_FRAME_BODY) {
|
||||
die("expected body, got frame type 0x%X", frame.frame_type);
|
||||
}
|
||||
|
||||
write_all(fd, frame.payload.body_fragment);
|
||||
body_remaining -= frame.payload.body_fragment.len;
|
||||
}
|
||||
}
|
||||
|
||||
poptContext process_options(int argc, const char **argv,
|
||||
struct poptOption *options, const char *help) {
|
||||
int c;
|
||||
poptContext opts = poptGetContext(NULL, argc, argv, options, 0);
|
||||
poptSetOtherOptionHelp(opts, help);
|
||||
|
||||
while ((c = poptGetNextOpt(opts)) >= 0) {
|
||||
/* no options require explicit handling */
|
||||
}
|
||||
|
||||
if (c < -1) {
|
||||
fprintf(stderr, "%s: %s\n", poptBadOption(opts, POPT_BADOPTION_NOALIAS),
|
||||
poptStrerror(c));
|
||||
poptPrintUsage(opts, stderr, 0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
void process_all_options(int argc, const char **argv,
|
||||
struct poptOption *options) {
|
||||
poptContext opts = process_options(argc, argv, options, "[OPTIONS]...");
|
||||
const char *opt = poptPeekArg(opts);
|
||||
|
||||
if (opt) {
|
||||
fprintf(stderr, "unexpected operand: %s\n", opt);
|
||||
poptPrintUsage(opts, stderr, 0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
poptFreeContext(opts);
|
||||
}
|
||||
|
||||
amqp_bytes_t cstring_bytes(const char *str) {
|
||||
return str ? amqp_cstring_bytes(str) : amqp_empty_bytes;
|
||||
}
|
73
ext/librabbitmq/tools/common.h
Normal file
73
ext/librabbitmq/tools/common.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* ***** 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 <stdint.h>
|
||||
|
||||
#include <popt.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_framing.h>
|
||||
|
||||
extern const char *amqp_server_exception_string(amqp_rpc_reply_t r);
|
||||
extern const char *amqp_rpc_reply_string(amqp_rpc_reply_t r);
|
||||
|
||||
extern void die(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
extern void die_errno(int err, const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
extern void die_amqp_error(int err, const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
extern void die_rpc(amqp_rpc_reply_t r, const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
extern const char *connect_options_title;
|
||||
extern struct poptOption connect_options[];
|
||||
extern amqp_connection_state_t make_connection(void);
|
||||
extern void close_connection(amqp_connection_state_t conn);
|
||||
|
||||
extern amqp_bytes_t read_all(int fd);
|
||||
extern void write_all(int fd, amqp_bytes_t data);
|
||||
|
||||
extern void copy_body(amqp_connection_state_t conn, int fd);
|
||||
|
||||
#define INCLUDE_OPTIONS(options) \
|
||||
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, options, 0, options##_title, NULL }
|
||||
|
||||
extern poptContext process_options(int argc, const char **argv,
|
||||
struct poptOption *options,
|
||||
const char *help);
|
||||
extern void process_all_options(int argc, const char **argv,
|
||||
struct poptOption *options);
|
||||
|
||||
extern amqp_bytes_t cstring_bytes(const char *str);
|
250
ext/librabbitmq/tools/consume.c
Normal file
250
ext/librabbitmq/tools/consume.c
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* ***** 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "process.h"
|
||||
|
||||
#define MAX_LISTEN_KEYS 1024
|
||||
#define LISTEN_KEYS_DELIMITER ","
|
||||
|
||||
/* Convert a amqp_bytes_t to an escaped string form for printing. We
|
||||
use the same escaping conventions as rabbitmqctl. */
|
||||
static char *stringify_bytes(amqp_bytes_t bytes) {
|
||||
/* We will need up to 4 chars per byte, plus the terminating 0 */
|
||||
char *res = malloc(bytes.len * 4 + 1);
|
||||
uint8_t *data = bytes.bytes;
|
||||
char *p = res;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < bytes.len; i++) {
|
||||
if (data[i] >= 32 && data[i] != 127) {
|
||||
*p++ = data[i];
|
||||
} else {
|
||||
*p++ = '\\';
|
||||
*p++ = '0' + (data[i] >> 6);
|
||||
*p++ = '0' + (data[i] >> 3 & 0x7);
|
||||
*p++ = '0' + (data[i] & 0x7);
|
||||
}
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
static amqp_bytes_t setup_queue(amqp_connection_state_t conn, char *queue,
|
||||
char *exchange, char *routing_key, int declare,
|
||||
int exclusive) {
|
||||
amqp_bytes_t queue_bytes = cstring_bytes(queue);
|
||||
|
||||
char *routing_key_rest;
|
||||
char *routing_key_token;
|
||||
char *routing_tmp;
|
||||
int routing_key_count = 0;
|
||||
|
||||
/* if an exchange name wasn't provided, check that we don't have options that
|
||||
* require it. */
|
||||
if (!exchange && routing_key) {
|
||||
fprintf(stderr,
|
||||
"--routing-key option requires an exchange name to be provided "
|
||||
"with --exchange\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!queue || exchange || declare || exclusive) {
|
||||
/* Declare the queue as auto-delete. */
|
||||
amqp_queue_declare_ok_t *res = amqp_queue_declare(
|
||||
conn, 1, queue_bytes, 0, 0, exclusive, 1, amqp_empty_table);
|
||||
if (!res) {
|
||||
die_rpc(amqp_get_rpc_reply(conn), "queue.declare");
|
||||
}
|
||||
|
||||
if (!queue) {
|
||||
/* the server should have provided a queue name */
|
||||
char *sq;
|
||||
queue_bytes = amqp_bytes_malloc_dup(res->queue);
|
||||
sq = stringify_bytes(queue_bytes);
|
||||
fprintf(stderr, "Server provided queue name: %s\n", sq);
|
||||
free(sq);
|
||||
}
|
||||
|
||||
/* Bind to an exchange if requested */
|
||||
if (exchange) {
|
||||
amqp_bytes_t eb = amqp_cstring_bytes(exchange);
|
||||
|
||||
routing_tmp = strdup(routing_key);
|
||||
if (NULL == routing_tmp) {
|
||||
fprintf(stderr, "could not allocate memory to parse routing key\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (routing_key_token =
|
||||
strtok_r(routing_tmp, LISTEN_KEYS_DELIMITER, &routing_key_rest);
|
||||
NULL != routing_key_token && routing_key_count < MAX_LISTEN_KEYS - 1;
|
||||
routing_key_token =
|
||||
strtok_r(NULL, LISTEN_KEYS_DELIMITER, &routing_key_rest)) {
|
||||
|
||||
if (!amqp_queue_bind(conn, 1, queue_bytes, eb,
|
||||
cstring_bytes(routing_key_token),
|
||||
amqp_empty_table)) {
|
||||
die_rpc(amqp_get_rpc_reply(conn), "queue.bind");
|
||||
}
|
||||
}
|
||||
free(routing_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return queue_bytes;
|
||||
}
|
||||
|
||||
#define AMQP_CONSUME_MAX_PREFETCH_COUNT 65535
|
||||
|
||||
static void do_consume(amqp_connection_state_t conn, amqp_bytes_t queue,
|
||||
int no_ack, int count, int prefetch_count,
|
||||
const char *const *argv) {
|
||||
int i;
|
||||
|
||||
/* If there is a limit, set the qos to match */
|
||||
if (count > 0 && count <= AMQP_CONSUME_MAX_PREFETCH_COUNT &&
|
||||
!amqp_basic_qos(conn, 1, 0, count, 0)) {
|
||||
die_rpc(amqp_get_rpc_reply(conn), "basic.qos");
|
||||
}
|
||||
|
||||
/* if there is a maximum number of messages to be received at a time, set the
|
||||
* qos to match */
|
||||
if (prefetch_count > 0 && prefetch_count <= AMQP_CONSUME_MAX_PREFETCH_COUNT) {
|
||||
/* the maximum number of messages to be received at a time must be less
|
||||
* than the global maximum number of messages. */
|
||||
if (!(count > 0 && count <= AMQP_CONSUME_MAX_PREFETCH_COUNT &&
|
||||
prefetch_count >= count)) {
|
||||
if (!amqp_basic_qos(conn, 1, 0, prefetch_count, 0)) {
|
||||
die_rpc(amqp_get_rpc_reply(conn), "basic.qos");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!amqp_basic_consume(conn, 1, queue, amqp_empty_bytes, 0, no_ack, 0,
|
||||
amqp_empty_table)) {
|
||||
die_rpc(amqp_get_rpc_reply(conn), "basic.consume");
|
||||
}
|
||||
|
||||
for (i = 0; count < 0 || i < count; i++) {
|
||||
amqp_frame_t frame;
|
||||
struct pipeline pl;
|
||||
uint64_t delivery_tag;
|
||||
amqp_basic_deliver_t *deliver;
|
||||
int res = amqp_simple_wait_frame(conn, &frame);
|
||||
die_amqp_error(res, "waiting for header frame");
|
||||
|
||||
if (frame.frame_type != AMQP_FRAME_METHOD ||
|
||||
frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
deliver = (amqp_basic_deliver_t *)frame.payload.method.decoded;
|
||||
delivery_tag = deliver->delivery_tag;
|
||||
|
||||
pipeline(argv, &pl);
|
||||
copy_body(conn, pl.infd);
|
||||
|
||||
if (finish_pipeline(&pl) && !no_ack)
|
||||
die_amqp_error(amqp_basic_ack(conn, 1, delivery_tag, 0), "basic.ack");
|
||||
|
||||
amqp_maybe_release_buffers(conn);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
poptContext opts;
|
||||
amqp_connection_state_t conn;
|
||||
const char *const *cmd_argv;
|
||||
static char *queue = NULL;
|
||||
static char *exchange = NULL;
|
||||
static char *routing_key = NULL;
|
||||
static int declare = 0;
|
||||
static int exclusive = 0;
|
||||
static int no_ack = 0;
|
||||
static int count = -1;
|
||||
static int prefetch_count = -1;
|
||||
amqp_bytes_t queue_bytes;
|
||||
|
||||
struct poptOption options[] = {
|
||||
INCLUDE_OPTIONS(connect_options),
|
||||
{"queue", 'q', POPT_ARG_STRING, &queue, 0, "the queue to consume from",
|
||||
"queue"},
|
||||
{"exchange", 'e', POPT_ARG_STRING, &exchange, 0,
|
||||
"bind the queue to this exchange", "exchange"},
|
||||
{"routing-key", 'r', POPT_ARG_STRING, &routing_key, 0,
|
||||
"the routing key to bind with", "routing key"},
|
||||
{"declare", 'd', POPT_ARG_NONE, &declare, 0,
|
||||
"declare an exclusive queue (deprecated, use --exclusive instead)",
|
||||
NULL},
|
||||
{"exclusive", 'x', POPT_ARG_NONE, &exclusive, 0,
|
||||
"declare the queue as exclusive", NULL},
|
||||
{"no-ack", 'A', POPT_ARG_NONE, &no_ack, 0, "consume in no-ack mode",
|
||||
NULL},
|
||||
{"count", 'c', POPT_ARG_INT, &count, 0,
|
||||
"stop consuming after this many messages are consumed", "limit"},
|
||||
{"prefetch-count", 'p', POPT_ARG_INT, &prefetch_count, 0,
|
||||
"receive only this many message at a time from the server", "limit"},
|
||||
POPT_AUTOHELP{NULL, '\0', 0, NULL, 0, NULL, NULL}};
|
||||
|
||||
opts = process_options(argc, argv, options, "[OPTIONS]... <command> <args>");
|
||||
|
||||
cmd_argv = poptGetArgs(opts);
|
||||
if (!cmd_argv || !cmd_argv[0]) {
|
||||
fprintf(stderr, "consuming command not specified\n");
|
||||
poptPrintUsage(opts, stderr, 0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
conn = make_connection();
|
||||
queue_bytes =
|
||||
setup_queue(conn, queue, exchange, routing_key, declare, exclusive);
|
||||
do_consume(conn, queue_bytes, no_ack, count, prefetch_count, cmd_argv);
|
||||
close_connection(conn);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
poptFreeContext(opts);
|
||||
return 1;
|
||||
}
|
79
ext/librabbitmq/tools/declare_queue.c
Normal file
79
ext/librabbitmq/tools/declare_queue.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* ***** 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
amqp_connection_state_t conn;
|
||||
static char *queue = NULL;
|
||||
static int durable = 0;
|
||||
|
||||
struct poptOption options[] = {
|
||||
INCLUDE_OPTIONS(connect_options),
|
||||
{"queue", 'q', POPT_ARG_STRING, &queue, 0,
|
||||
"the queue name to declare, or the empty string", "queue"},
|
||||
{"durable", 'd', POPT_ARG_VAL, &durable, 1, "declare a durable queue",
|
||||
NULL},
|
||||
POPT_AUTOHELP{NULL, '\0', 0, NULL, 0, NULL, NULL}};
|
||||
|
||||
process_all_options(argc, argv, options);
|
||||
|
||||
if (queue == NULL) {
|
||||
fprintf(stderr, "queue name not specified\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
conn = make_connection();
|
||||
{
|
||||
amqp_queue_declare_ok_t *reply = amqp_queue_declare(
|
||||
conn, 1, cstring_bytes(queue), 0, durable, 0, 0, amqp_empty_table);
|
||||
if (reply == NULL) {
|
||||
die_rpc(amqp_get_rpc_reply(conn), "queue.declare");
|
||||
}
|
||||
|
||||
printf("%.*s\n", (int)reply->queue.len, (char *)reply->queue.bytes);
|
||||
}
|
||||
close_connection(conn);
|
||||
return 0;
|
||||
}
|
81
ext/librabbitmq/tools/delete_queue.c
Normal file
81
ext/librabbitmq/tools/delete_queue.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* ***** 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
amqp_connection_state_t conn;
|
||||
static char *queue = NULL;
|
||||
static int if_unused = 0;
|
||||
static int if_empty = 0;
|
||||
|
||||
struct poptOption options[] = {
|
||||
INCLUDE_OPTIONS(connect_options),
|
||||
{"queue", 'q', POPT_ARG_STRING, &queue, 0, "the queue name to delete",
|
||||
"queue"},
|
||||
{"if-unused", 'u', POPT_ARG_VAL, &if_unused, 1,
|
||||
"do not delete unless queue is unused", NULL},
|
||||
{"if-empty", 'e', POPT_ARG_VAL, &if_empty, 1,
|
||||
"do not delete unless queue is empty", NULL},
|
||||
POPT_AUTOHELP{NULL, '\0', 0, NULL, 0, NULL, NULL}};
|
||||
|
||||
process_all_options(argc, argv, options);
|
||||
|
||||
if (queue == NULL || *queue == '\0') {
|
||||
fprintf(stderr, "queue name not specified\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
conn = make_connection();
|
||||
{
|
||||
amqp_queue_delete_ok_t *reply =
|
||||
amqp_queue_delete(conn, 1, cstring_bytes(queue), if_unused, if_empty);
|
||||
if (reply == NULL) {
|
||||
die_rpc(amqp_get_rpc_reply(conn), "queue.delete");
|
||||
}
|
||||
printf("%u\n", reply->message_count);
|
||||
}
|
||||
close_connection(conn);
|
||||
return 0;
|
||||
}
|
223
ext/librabbitmq/tools/doc/amqp-consume.xml
Normal file
223
ext/librabbitmq/tools/doc/amqp-consume.xml
Normal file
|
@ -0,0 +1,223 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.docbook.org/xml/4.5/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY date SYSTEM "man-date.ent" >
|
||||
]
|
||||
>
|
||||
<refentry lang="en">
|
||||
<refentryinfo>
|
||||
<productname>RabbitMQ C Client</productname>
|
||||
<authorgroup>
|
||||
<corpauthor>The RabbitMQ Team <<ulink url="mailto:info@rabbitmq.com"><email>info@rabbitmq.com</email></ulink>></corpauthor>
|
||||
</authorgroup>
|
||||
<date>&date;</date>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>amqp-consume</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">RabbitMQ C Client</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>amqp-consume</refname>
|
||||
<refpurpose>Consume messages from a queue on an AMQP server</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>amqp-consume</command>
|
||||
<arg choice="opt" rep="repeat">
|
||||
<replaceable>OPTION</replaceable>
|
||||
</arg>
|
||||
<arg choice="req">
|
||||
<replaceable>command</replaceable>
|
||||
</arg>
|
||||
<arg choice="opt" rep="repeat">
|
||||
<replaceable>args</replaceable>
|
||||
</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
<command>amqp-consume</command> consumes messages from a
|
||||
queue on an AMQP server. For each message that arrives, a
|
||||
receiving command is run, with the message body supplied
|
||||
to it on standard input.
|
||||
</para>
|
||||
<para>
|
||||
<command>amqp-consume</command> can consume from an
|
||||
existing queue, or it can create a new queue. It can
|
||||
optionally bind the queue to an existing exchange.
|
||||
</para>
|
||||
<para>
|
||||
By default, messages will be consumed with explicit
|
||||
acknowledgements. A message will only be acknowledged if
|
||||
the receiving command exits successfully (i.e. with an
|
||||
exit code of zero). The AMQP <quote>no ack</quote> mode
|
||||
(a.k.a. auto-ack mode) can be enable with the
|
||||
<option>-A</option> option.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-q</option></term>
|
||||
<term><option>--queue</option>=<replaceable class="parameter">queue name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of the queue to consume messages
|
||||
from.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the <option>--queue</option> option is
|
||||
omitted, the AMQP server will assign a unique
|
||||
name to the queue, and that server-assigned
|
||||
name will be dixsplayed on stderr; this case
|
||||
implies that an exclusive queue should be
|
||||
declared.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-e</option></term>
|
||||
<term><option>--exchange</option>=<replaceable class="parameter">exchange name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies that an exclusive queue should
|
||||
be declared, and bound to the given exchange.
|
||||
The specified exchange should already exist
|
||||
unless the <option>--exchange-type</option>
|
||||
option is used to request the creation of an
|
||||
exchange.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-r</option></term>
|
||||
<term><option>--routing-key</option>=<replaceable class="parameter">routing key</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The routing key for binding. If omitted, an
|
||||
empty routing key is assumed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-d</option></term>
|
||||
<term><option>--declare</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Forces an exclusive queue to be declared,
|
||||
even when it otherwise would not be. That is,
|
||||
when a queue name is specified with the
|
||||
<option>--queue</option> option, but no
|
||||
binding to an exchange is requested with the
|
||||
<option>--exchange</option> option.
|
||||
Note: this option is deprecated and may be
|
||||
removed in a future version, use the
|
||||
<option>--exclusive</option> option to
|
||||
explicitly declare an exclusive queue.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-x</option></term>
|
||||
<term><option>--exclusive</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Declared queues are non-exclusive by default,
|
||||
this option forces declaration of exclusive
|
||||
queues.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-A</option></term>
|
||||
<term><option>--no-ack</option>=<replaceable class="parameter">routing key</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Enable <quote>no ack</quote> mode: The AMQP
|
||||
server will unconditionally acknowledge each
|
||||
message that is delivered, regardless of
|
||||
whether the target command exits successfully
|
||||
or not.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-c</option></term>
|
||||
<term><option>--count</option>=<replaceable class="parameter">limit</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Stop consuming after the given number of
|
||||
messages have been received.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-p</option></term>
|
||||
<term><option>--prefetch-count</option>=<replaceable class="parameter">limit</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Request the server to only send
|
||||
<replaceable class="parameter">limit</replaceable>
|
||||
messages at a time.
|
||||
</para>
|
||||
<para>
|
||||
If any value was passed to <option>--count</option>,
|
||||
the value passed to <option>--prefetch-count</option>
|
||||
should be smaller than that, or otherwise it will be
|
||||
ignored.
|
||||
</para>
|
||||
<para>
|
||||
If <option>-A</option>/<option>--no-ack</option> is
|
||||
passed, this option has no effect.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>Consume messages from an existing queue
|
||||
<quote><systemitem
|
||||
class="resource">myqueue</systemitem></quote>, and
|
||||
output the message bodies on standard output via
|
||||
<command>cat</command>:</term>
|
||||
<listitem>
|
||||
<screen><prompt>$ </prompt><userinput>amqp-publish -q myqueue cat</userinput></screen>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Bind a new exclusive queue to an
|
||||
exchange <quote><systemitem
|
||||
class="resource">myexch</systemitem></quote>, and send
|
||||
each message body to the script
|
||||
<filename>myscript</filename>, automatically
|
||||
acknowledging them on the server:</term>
|
||||
<listitem>
|
||||
<screen><prompt>$ </prompt><userinput>amqp-consume -A -e myexch ./myscript</userinput></screen>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>librabbitmq-tools</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
describes connection-related options common to all the
|
||||
RabbitMQ C Client tools.
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
122
ext/librabbitmq/tools/doc/amqp-declare-queue.xml
Normal file
122
ext/librabbitmq/tools/doc/amqp-declare-queue.xml
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.docbook.org/xml/4.5/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY date SYSTEM "man-date.ent" >
|
||||
]
|
||||
>
|
||||
<refentry lang="en">
|
||||
<refentryinfo>
|
||||
<productname>RabbitMQ C Client</productname>
|
||||
<authorgroup>
|
||||
<corpauthor>The RabbitMQ Team <<ulink url="mailto:info@rabbitmq.com"><email>info@rabbitmq.com</email></ulink>></corpauthor>
|
||||
</authorgroup>
|
||||
<date>&date;</date>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>amqp-declare-queue</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">RabbitMQ C Client</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>amqp-declare-queue</refname>
|
||||
<refpurpose>Declare (create or assert the existence of) a queue on an AMQP server</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>amqp-declare-queue</command>
|
||||
<arg choice="opt" rep="repeat">
|
||||
<replaceable>OPTION</replaceable>
|
||||
</arg>
|
||||
<arg choice="opt">-d</arg>
|
||||
<arg choice="req">-q <replaceable>queue name</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
<command>amqp-declare-queue</command> attempts to create a
|
||||
queue on an AMQP server, and exits. If the empty-string is
|
||||
supplied as the queue name, a fresh queue name is
|
||||
generated by the server and returned. In all cases, if a
|
||||
queue was successfully declared, the (raw binary) name of
|
||||
the queue is printed to standard output, followed by a
|
||||
newline.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-q</option></term>
|
||||
<term><option>--queue</option>=<replaceable class="parameter">queue name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of the queue to declare. If the
|
||||
empty string is supplied, a fresh queue name
|
||||
is generated by the server.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-d</option></term>
|
||||
<term><option>--durable</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Causes the queue to be declared with the
|
||||
"durable" flag set. Durable queues survive
|
||||
server restarts. By default, queues are declared
|
||||
in "transient" mode.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit Status</title>
|
||||
<para>
|
||||
If the queue was successfully declared, the exit status is
|
||||
0. If an error occurs, the exit status is 1.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>Declare the durable queue <quote><systemitem
|
||||
class="resource">myqueue</systemitem></quote>, and
|
||||
display the name of the queue on standard output:</term>
|
||||
<listitem>
|
||||
<screen><prompt>$ </prompt><userinput>amqp-declare-queue -d -q myqueue</userinput>
|
||||
myqueue</screen>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Declare a fresh, server-named transient queue,
|
||||
and display the name of the queue on standard output
|
||||
(use <citerefentry><refentrytitle>amqp-delete-queue</refentrytitle>
|
||||
<manvolnum>1</manvolnum></citerefentry> to delete
|
||||
it from the server once you're done):</term>
|
||||
<listitem>
|
||||
<screen><prompt>$ </prompt><userinput>amqp-declare-queue -q ""</userinput>
|
||||
amq.gen-BW/wvociA8g6LFpb1PlqOA==</screen>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>librabbitmq-tools</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
describes connection-related options common to all the
|
||||
RabbitMQ C Client tools.
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
94
ext/librabbitmq/tools/doc/amqp-delete-queue.xml
Normal file
94
ext/librabbitmq/tools/doc/amqp-delete-queue.xml
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.docbook.org/xml/4.5/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY date SYSTEM "man-date.ent" >
|
||||
]
|
||||
>
|
||||
<refentry lang="en">
|
||||
<refentryinfo>
|
||||
<productname>RabbitMQ C Client</productname>
|
||||
<authorgroup>
|
||||
<corpauthor>The RabbitMQ Team <<ulink url="mailto:info@rabbitmq.com"><email>info@rabbitmq.com</email></ulink>></corpauthor>
|
||||
</authorgroup>
|
||||
<date>&date;</date>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>amqp-delete-queue</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">RabbitMQ C Client</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>amqp-delete-queue</refname>
|
||||
<refpurpose>Delete a queue from an AMQP server</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>amqp-delete-queue</command>
|
||||
<arg choice="opt" rep="repeat">
|
||||
<replaceable>OPTION</replaceable>
|
||||
</arg>
|
||||
<arg choice="req">-q <replaceable>queue name</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
<command>amqp-delete-queue</command> deletes a queue from
|
||||
an AMQP server, and exits after printing to standard
|
||||
output the number of messages that were in the queue at
|
||||
the time of its deletion.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-q</option></term>
|
||||
<term><option>--queue</option>=<replaceable class="parameter">queue name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of the queue to delete.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit Status</title>
|
||||
<para>
|
||||
If the queue was successfully deleted, the exit status is
|
||||
0. If an error occurs, the exit status is 1.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>Delete the
|
||||
queue <quote><systemitem class="resource">myqueue</systemitem></quote>
|
||||
at a moment when it has 123 messages waiting on
|
||||
it:</term>
|
||||
<listitem>
|
||||
<screen><prompt>$ </prompt><userinput>amqp-delete-queue -q myqueue</userinput>
|
||||
123</screen>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>librabbitmq-tools</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
describes connection-related options common to all the
|
||||
RabbitMQ C Client tools.
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
95
ext/librabbitmq/tools/doc/amqp-get.xml
Normal file
95
ext/librabbitmq/tools/doc/amqp-get.xml
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.docbook.org/xml/4.5/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY date SYSTEM "man-date.ent" >
|
||||
]
|
||||
>
|
||||
<refentry lang="en">
|
||||
<refentryinfo>
|
||||
<productname>RabbitMQ C Client</productname>
|
||||
<authorgroup>
|
||||
<corpauthor>The RabbitMQ Team <<ulink url="mailto:info@rabbitmq.com"><email>info@rabbitmq.com</email></ulink>></corpauthor>
|
||||
</authorgroup>
|
||||
<date>&date;</date>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>amqp-get</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">RabbitMQ C Client</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>amqp-get</refname>
|
||||
<refpurpose>Get a message from a queue on an AMQP server</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>amqp-get</command>
|
||||
<arg choice="opt" rep="repeat">
|
||||
<replaceable>OPTION</replaceable>
|
||||
</arg>
|
||||
<arg choice="req">-q <replaceable>queue name</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
<command>amqp-get</command> attempts to consume a single
|
||||
message from a queue on an AMQP server, and exits. Unless
|
||||
the queue was empty, the body of the resulting message is
|
||||
sent to standard output.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-q</option></term>
|
||||
<term><option>--queue</option>=<replaceable class="parameter">queue name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of the queue to consume messages
|
||||
from.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit Status</title>
|
||||
<para>
|
||||
If the queue is not empty, and a message is successfully
|
||||
retrieved, the exit status is 0. If an error occurs, the
|
||||
exit status is 1. If the queue is found to be empty, the
|
||||
exit status is 2.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>Get a message from the queue <quote><systemitem
|
||||
class="resource">myqueue</systemitem></quote>, and
|
||||
display its body on standard output:</term>
|
||||
<listitem>
|
||||
<screen><prompt>$ </prompt><userinput>amqp-get -q myqueue</userinput></screen>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>librabbitmq-tools</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
describes connection-related options common to all the
|
||||
RabbitMQ C Client tools.
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
169
ext/librabbitmq/tools/doc/amqp-publish.xml
Normal file
169
ext/librabbitmq/tools/doc/amqp-publish.xml
Normal file
|
@ -0,0 +1,169 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.docbook.org/xml/4.5/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY date SYSTEM "man-date.ent" >
|
||||
]
|
||||
>
|
||||
<refentry lang="en">
|
||||
<refentryinfo>
|
||||
<productname>RabbitMQ C Client</productname>
|
||||
<authorgroup>
|
||||
<corpauthor>The RabbitMQ Team <<ulink url="mailto:info@rabbitmq.com"><email>info@rabbitmq.com</email></ulink>></corpauthor>
|
||||
</authorgroup>
|
||||
<date>&date;</date>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>amqp-publish</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">RabbitMQ C Client</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>amqp-publish</refname>
|
||||
<refpurpose>Publish a message on an AMQP server</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>amqp-publish</command>
|
||||
<arg choice="opt" rep="repeat">
|
||||
<replaceable>OPTION</replaceable>
|
||||
</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
Publishes a message to an exchange on an AMQP server.
|
||||
Options allow the various properties of the message and
|
||||
parameters of the AMQP <function>basic.publish</function>
|
||||
method to be specified.
|
||||
</para>
|
||||
<para>
|
||||
By default, the message body is read from standard input.
|
||||
Alternatively, the <option>-b</option> option allows the message
|
||||
body to be provided as part of the command.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-e</option></term>
|
||||
<term><option>--exchange</option>=<replaceable class="parameter">exchange name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of the exchange to publish to. If
|
||||
omitted, the default exchange (also known as
|
||||
the nameless exchange) is used.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-r</option></term>
|
||||
<term><option>--routing-key</option>=<replaceable class="parameter">routing key</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The routing key to publish with. If omitted,
|
||||
an empty routing key is assumed. A routing
|
||||
key must be specified when publishing to the
|
||||
default exchange; in that case, accoding to
|
||||
the AMQP specification, the routing key
|
||||
corresponds to a queue name.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-p</option></term>
|
||||
<term><option>--persistent</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the persistent delivery mode. Without
|
||||
this option, non-persistent delivery is used.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-C</option></term>
|
||||
<term><option>--content-type</option>=<replaceable class="parameter">MIME type</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies the content-type property for the
|
||||
message. If omitted, the content-type
|
||||
property is not set on the message.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-E</option></term>
|
||||
<term><option>--content-encoding</option>=<replaceable class="parameter">content coding</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies the content-encoding property for
|
||||
the message. If omitted, the content-encoding
|
||||
property is not set on the message.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-b</option></term>
|
||||
<term><option>--body</option>=<replaceable class="parameter">message body</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies the message body. If omitted, the
|
||||
message body is read from standard input.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-H</option></term>
|
||||
<term><option>--header</option>=<replaceable class="parameter">header</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies an optional header in the form "key: value".
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>Send a short message, consisting of the word
|
||||
<quote><literal>Hello</literal></quote> to the queue
|
||||
<quote><systemitem
|
||||
class="resource">myqueue</systemitem></quote> via the
|
||||
default exchange:</term>
|
||||
<listitem>
|
||||
<screen><prompt>$ </prompt><userinput>amqp-publish -r myqueue -b Hello</userinput></screen>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Send some XML data from a file to the exchange
|
||||
<quote><systemitem
|
||||
class="resource">events</systemitem></quote>, with
|
||||
persistent delivery mode, setting the content-type
|
||||
property on the message to make the data format
|
||||
explicit:</term>
|
||||
<listitem>
|
||||
<screen><prompt>$ </prompt><userinput>amqp-publish -e events -p -C text/xml <event.xml</userinput></screen>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>librabbitmq-tools</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
describes connection-related options common to all the
|
||||
RabbitMQ C Client tools.
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
90
ext/librabbitmq/tools/doc/librabbitmq-tools.xml
Normal file
90
ext/librabbitmq/tools/doc/librabbitmq-tools.xml
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.docbook.org/xml/4.5/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY date SYSTEM "man-date.ent" >
|
||||
]
|
||||
>
|
||||
<refentry lang="en">
|
||||
<refentryinfo>
|
||||
<productname>RabbitMQ C Client</productname>
|
||||
<authorgroup>
|
||||
<corpauthor>The RabbitMQ Team <<ulink url="mailto:info@rabbitmq.com"><email>info@rabbitmq.com</email></ulink>></corpauthor>
|
||||
</authorgroup>
|
||||
<date>&date;</date>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>librabbitmq-tools</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
<refmiscinfo class="manual">RabbitMQ C Client</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>librabbitmq-tools</refname>
|
||||
<refpurpose>Command line AMQP tools</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
A set of command line AMQP tools based on <systemitem
|
||||
class="library">librabbitmq</systemitem>. This page
|
||||
describes common options and conventions used by all of
|
||||
the tools.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Common Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-s</option></term>
|
||||
<term><option>--server</option>=<replaceable class="parameter">hostname:port</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The host name (or address) to connect to.
|
||||
Defaults to localhost. The port number may
|
||||
also be specified; if omitted, it defaults to
|
||||
the standard AMQP port number (5672).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--vhost</option>=<replaceable class="parameter">vhost</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The AMQP vhost to specify when connecting.
|
||||
Defaults to <literal>/</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--username</option>=<replaceable class="parameter">username</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The username to authenticate to the AMQP server with. Defaults to <literal>guest</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--password</option>=<replaceable class="parameter">password</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The password to authenticate to the AMQP server with. Defaults to <literal>guest</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<simplelist type='inline'>
|
||||
<member><citerefentry><refentrytitle>amqp-publish</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>amqp-consume</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>amqp-get</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
78
ext/librabbitmq/tools/get.c
Normal file
78
ext/librabbitmq/tools/get.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* ***** 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 <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static int do_get(amqp_connection_state_t conn, char *queue) {
|
||||
amqp_rpc_reply_t r = amqp_basic_get(conn, 1, cstring_bytes(queue), 1);
|
||||
die_rpc(r, "basic.get");
|
||||
|
||||
if (r.reply.id == AMQP_BASIC_GET_EMPTY_METHOD) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
copy_body(conn, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
amqp_connection_state_t conn;
|
||||
static char *queue = NULL;
|
||||
int got_something;
|
||||
|
||||
struct poptOption options[] = {
|
||||
INCLUDE_OPTIONS(connect_options),
|
||||
{"queue", 'q', POPT_ARG_STRING, &queue, 0, "the queue to consume from",
|
||||
"queue"},
|
||||
POPT_AUTOHELP{NULL, '\0', 0, NULL, 0, NULL, NULL}};
|
||||
|
||||
process_all_options(argc, argv, options);
|
||||
|
||||
if (!queue) {
|
||||
fprintf(stderr, "queue not specified\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
conn = make_connection();
|
||||
got_something = do_get(conn, queue);
|
||||
close_connection(conn);
|
||||
return got_something ? 0 : 2;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue