This commit is contained in:
ewertons 2015-12-11 16:27:03 -08:00
Родитель 2d638492b6
Коммит f0003c4610
149 изменённых файлов: 77389 добавлений и 117 удалений

180
.gitignore поставляемый
Просмотреть файл

@ -7,3 +7,183 @@
*.opensdf
*.sdf
*.suo
*.~vsdx
*.lib
*.pdb
*.idb
*.obj
*.tlog
*.cache
*.exe
*.ilk
/src/amqplib.c~RF521d7ee.TMP
*.TMP
/amqplib/Debug
/Debug
/samples/send/Debug
/amqplib/Release
/Release
/samples/send/Release
*.zip
/Source/Native/ISSAgent/Windows/Win32/Release/MicroMock/MicroMock.pch
/Source/Native/ISSAgent/Windows/Win32/Debug/MicroMock/MicroMock.pch
/ipch/amqpvalue_unittests-1e17bc3d/amqpvalue_unittests-66ad55a4.ipch
*.ipch
/doc/~$st_requirements.docm
*.pch
*.user
/doc/~$qpvalue_requirements.docm
/doc/~$ster_requirements_doc.docm
/TestResults/amqplib.TE.Tests.mdf
/TestResults/amqplib.TE.Tests_log.ldf
/doc/~$_requirements.docm
/doc/~$nnection_requirements.docm
/doc/~$qp_frame_codec_requirements.docm
/doc/~$ame_codec_requirements.docm
*.codeanalysis
*.codeanalysisast
/Win32/Debug/micromock/micromockcharstararenullterminatedstrings.nativecodeanalysis.xml
/Win32/Debug/micromock/micromockexception.nativecodeanalysis.xml
/Win32/Debug/micromock/micromocktestmutex.nativecodeanalysis.xml
/Win32/Debug/micromock/mockcallrecorder.nativecodeanalysis.xml
/Win32/Debug/micromock/mockmethodcallbase.nativecodeanalysis.xml
/Win32/Debug/micromock/mockvaluebase.nativecodeanalysis.xml
/Win32/Debug/micromock/stdafx.nativecodeanalysis.xml
/Win32/Debug/micromock/timediscretemicromock.nativecodeanalysis.xml
/Win32/Debug/micromock/vc.nativecodeanalysis.all.xml
*.lastcodeanalysissucceeded
/amqplib_generator/amqplib_generator/obj/Debug/amqplib_generator.csproj.FileListAbsolute.txt
/amqplib_generator/amqplib_generator/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
/amqplib_generator/amqplib_generator/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
/amqplib_generator/amqplib_generator/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
/amqplib_generator/amqplib_generator/bin/Debug/amqplib_generator.exe.config
*.dll
*.config
/amqplib_generator/obj/Debug/amqplib_generator.csproj.FileListAbsolute.txt
/amqplib_generator/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
/amqplib_generator/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
/amqplib_generator/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
/amqplib_generator/bin/Debug/amqplib_generator.vshost.exe.manifest
/amqplib_generator/bin/Debug/amqplib_generator.exe.CodeAnalysisLog.xml
*.coverage
/amqplib_generator/obj/x64/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
/amqplib_generator/obj/x64/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
/amqplib_generator/obj/x64/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
/amqplib_generator/obj/x64/Debug/amqplib_generator.csproj.FileListAbsolute.txt
/amqplib_generator/bin/x64/Debug/amqplib_generator.vshost.exe.manifest
*.exp
/testtools/bnw_mock_c/doc/~$w_mock_c.docm
*.i
/amqplib_generator/obj/Release/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
/amqplib_generator/obj/Release/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
/amqplib_generator/obj/Release/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
/doc/~$sl_frame_codec_requirements.docm
/doc/~$ssion_requirements.docm
/c/amqplib_generator/obj/Debug/amqplib_generator.csproj.FileListAbsolute.txt
/c/amqplib_generator/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
/c/amqplib_generator/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
/c/amqplib_generator/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
/c/amqplib_generator/bin/Debug/amqplib_generator.vshost.exe.manifest
/c/TestResults/amqplib.TE.Tests.mdf
/c/TestResults/amqplib.TE.Tests_log.ldf
/c/amqplib_generator/bin/Debug/amqplib_generator.exe.CodeAnalysisLog.xml
/c/Debug/Win32/amqplib/amqpalloc.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/amqplib.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/amqpvalue.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/amqpvalue_to_string.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/amqp_definitions.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/amqp_frame_codec.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/connection.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/consolelogger.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/frame_codec.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/io.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/link.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/list.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/message.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/message_receiver.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/message_sender.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/messaging.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/platform_win32.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/saslio.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/sasl_frame_codec.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/sasl_mechanism.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/sasl_plain.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/session.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/socketio_win32.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/tlsio_win32.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/amqpvalue_limits_unittests/amqpvalue_limits_unittests.nativecodeanalysis.xml
/c/Debug/Win32/amqpvalue_limits_unittests/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/amqpvalue_unittests
/c/Debug/Win32/amqpvalue_unittests/amqpvalue_unittests.nativecodeanalysis.xml
/c/Debug/Win32/amqpvalue_unittests/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/amqp_frame_codec_unittests
/c/Debug/Win32/amqp_frame_codec_unittests/amqp_frame_codec_unittests.nativecodeanalysis.xml
/c/Debug/Win32/amqp_frame_codec_unittests/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/connection_unittests
/c/Debug/Win32/connection_unittests/connection_unittests.nativecodeanalysis.xml
/c/Debug/Win32/connection_unittests/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/frame_codec_unittests
/c/Debug/Win32/frame_codec_unittests/frame_codec_unittests.nativecodeanalysis.xml
/c/Debug/Win32/frame_codec_unittests/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/io_unittests
/c/Debug/Win32/io_unittests/io_unittests.nativecodeanalysis.xml
/c/Debug/Win32/io_unittests/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/list_unittests
/c/Debug/Win32/list_unittests/list_unittests.nativecodeanalysis.xml
/c/Debug/Win32/list_unittests/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/message_receiver
/c/Debug/Win32/message_receiver/main.nativecodeanalysis.xml
/c/Debug/Win32/message_receiver/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/message_sender
/c/Debug/Win32/message_sender/main.nativecodeanalysis.xml
/c/Debug/Win32/message_sender/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/sasl_frame_codec_unittests
/c/Debug/Win32/sasl_frame_codec_unittests/sasl_frame_codec_unittests.nativecodeanalysis.xml
/c/Debug/Win32/sasl_frame_codec_unittests/vc.nativecodeanalysis.all.xml
/c/Debug/Win32/session_unittests
/c/Debug/Win32/session_unittests/session_unittests.nativecodeanalysis.xml
/c/Debug/Win32/session_unittests/vc.nativecodeanalysis.all.xml
/c/Win32/Debug/micromock
/c/Win32/Debug/micromock/micromockcharstararenullterminatedstrings.nativecodeanalysis.xml
/c/Win32/Debug/micromock/micromockexception.nativecodeanalysis.xml
/c/Win32/Debug/micromock/micromocktestmutex.nativecodeanalysis.xml
/c/Win32/Debug/micromock/mockcallrecorder.nativecodeanalysis.xml
/c/Win32/Debug/micromock/mockmethodcallbase.nativecodeanalysis.xml
/c/Win32/Debug/micromock/mockvaluebase.nativecodeanalysis.xml
/c/Win32/Debug/micromock/stdafx.nativecodeanalysis.xml
/c/doc/~$_requirements.docm
/c/doc/~$ssage_requirements.docm
/c/Debug/Win32/amqplib/cbs.nativecodeanalysis.xml
/c/Debug/Win32/amqplib/sasl_mssbcbs.nativecodeanalysis.xml
/c/Debug/Win32/message_unittests
/c/Debug/Win32/message_unittests/message_unittests.nativecodeanalysis.xml
/c/Debug/Win32/message_unittests/vc.nativecodeanalysis.all.xml
/c/cmake/**
/c/doc/~$ame_codec_requirements.docm
/c/doc/~$st_requirements.docm
/c/uamqp_generator/bin/Debug/amqplib_generator.vshost.exe.manifest
/c/uamqp_generator/obj/Debug/uamqp_generator.csproj.FileListAbsolute.txt
/c/uamqp_generator/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
/c/uamqp_generator/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
/c/uamqp_generator/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
/c/doc/~$sl_anonymous.docm
/c/doc/~$sl_mechanism_requirements.docm
/c/doc/~$slio_requirements.docm
/c/doc/~$qpvalue_requirements.docm
/c/doc/~$sl_frame_codec_requirements.docm
/all.pem
/baltimore.der
/baltimore.pem
/msit.der
/msit.pem
/sb.der
/sb.pem
/uamqp_generator/bin/Debug/amqplib_generator.vshost.exe.manifest
/uamqp_generator/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
/uamqp_generator/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
/uamqp_generator/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
/uamqp_generator/obj/Debug/uamqp_generator.csproj.FileListAbsolute.txt
/build
/devdoc/~$slio_requirements.docm
/devdoc/~$slclientio_requirements.docm

3
.gitmodules поставляемый Normal file
Просмотреть файл

@ -0,0 +1,3 @@
[submodule "azure-c-shared-utility"]
path = azure-c-shared-utility
url = https://github.com/Azure/azure-c-shared-utility.git

292
CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,292 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
cmake_minimum_required(VERSION 3.0)
project(uamqp)
option(run_e2e_tests "set run_e2e_tests to ON to run e2e tests (default is OFF) [if possible, they are always build]" OFF)
option(run_longhaul_tests "set run_longhaul_tests to ON to run longhaul tests (default is OFF)[if possible, they are always build]" OFF)
option(skip_unittests "set skip_unittests to ON to skip unittests (default is OFF)[if possible, they are always build]" OFF)
option(leak_detection "set leak_detection to ON (default is OFF)" OFF)
option(compileOption_C "passes a string to the command line of the C compiler" OFF)
option(compileOption_CXX "passes a string to the command line of the C++ compiler" OFF)
option(wsio "set wsio to ON to use libwebsockets for WebSocket support (default is OFF)[if possible, they are always build]" OFF)
if(WIN32)
option(use_schannel "set use_schannel to ON if schannel is to be used, set to OFF to not use schannel" ON)
option(use_openssl "set use_openssl to ON if openssl is to be used, set to OFF to not use openssl" OFF)
option(use_wolfssl "set use_wolfssl to ON if wolfssl is to be used, set to OFF to not use wolfssl" OFF)
else()
option(use_schannel "set use_schannel to ON if schannel is to be used, set to OFF to not use schannel" OFF)
option(use_openssl "set use_openssl to ON if openssl is to be used, set to OFF to not use openssl" ON)
option(use_wolfssl "set use_wolfssl to ON if wolfssl is to be used, set to OFF to not use wolfssl" OFF)
endif()
#Use solution folders.
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
add_subdirectory(azure-c-shared-utility/c)
enable_testing()
#if any compiler has a command line switch called "OFF" then it will need special care
if(NOT "${compileOption_C}" STREQUAL "OFF")
set(CMAKE_C_FLAGS "${compileOption_C} ${CMAKE_C_FLAGS}")
endif()
if(NOT "${compileOption_CXX}" STREQUAL "OFF")
set(CMAKE_CXX_FLAGS "${compileOption_CXX} ${CMAKE_CXX_FLAGS}")
endif()
#this project uses several other projects that are build not by these CMakeFiles
#this project also targets several OSes
#this function takes care of three things:
#1. copying some shared libraries(.dll or .so) to the location of the output executable
macro(compileAsC99)
if (CMAKE_VERSION VERSION_LESS "3.1")
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
set (CMAKE_C_FLAGS "--std=c99 ${CMAKE_C_FLAGS}")
set (CMAKE_CXX_FLAGS "--std=c++11 ${CMAKE_CXX_FLAGS}")
endif()
else()
set (CMAKE_C_STANDARD 99)
set (CMAKE_CXX_STANDARD 11)
endif()
endmacro(compileAsC99)
macro(compileAsC11)
if (CMAKE_VERSION VERSION_LESS "3.1")
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
set (CMAKE_C_FLAGS "--std=c11 ${CMAKE_C_FLAGS}")
set (CMAKE_C_FLAGS "-D_POSIX_C_SOURCE=200112L ${CMAKE_C_FLAGS}")
set (CMAKE_CXX_FLAGS "--std=c++11 ${CMAKE_CXX_FLAGS}")
endif()
else()
set (CMAKE_C_STANDARD 11)
set (CMAKE_CXX_STANDARD 11)
endif()
endmacro(compileAsC11)
function(windows_unittests_add_dll whatIsBuilding)
link_directories(${whatIsBuilding}_dll ${MICROMOCK_UNITTEST_LIB_DIR} ${CTEST_LIB_DIR} ${SHARED_UTIL_LIB_DIR} $ENV{VCInstallDir}UnitTest/lib)
add_library(${whatIsBuilding}_dll SHARED
${${whatIsBuilding}_cpp_files}
${${whatIsBuilding}_h_files}
${${whatIsBuilding}_c_files}
)
#Add UnitTests to their own folder
set_target_properties(${whatIsBuilding}_dll
PROPERTIES
FOLDER "UnitTests")
target_include_directories(${whatIsBuilding}_dll PUBLIC ${sharedutil_include_directories} $ENV{VCInstallDir}UnitTest/include)
target_compile_definitions(${whatIsBuilding}_dll PUBLIC -DCPP_UNITTEST)
target_link_libraries(${whatIsBuilding}_dll micromock_cpp_unittest ctest ${ARGN})
endfunction()
function(windows_unittests_add_exe whatIsBuilding)
link_directories(${whatIsBuilding}_exe ${MICROMOCK_UNITTEST_LIB_DIR} ${CTEST_LIB_DIR} ${SHARED_UTIL_LIB_DIR} $ENV{VCInstallDir}UnitTest/lib)
add_executable(${whatIsBuilding}_exe
${${whatIsBuilding}_cpp_files}
${${whatIsBuilding}_h_files}
${${whatIsBuilding}_c_files}
${CMAKE_CURRENT_LIST_DIR}/main.c
)
#Add UnitTests to their own folder
set_target_properties(${whatIsBuilding}_exe
PROPERTIES
FOLDER "UnitTests")
target_compile_definitions(${whatIsBuilding}_exe PUBLIC -DUSE_CTEST)
target_include_directories(${whatIsBuilding}_exe PUBLIC ${sharedutil_include_directories})
target_link_libraries(${whatIsBuilding}_exe micromock_ctest ctest ${ARGN})
add_test(NAME ${whatIsBuilding} COMMAND ${whatIsBuilding}_exe)
endfunction()
function(windows_unittests_add_lib whatIsBuilding)
link_directories(${whatIsBuilding}_lib ${MICROMOCK_UNITTEST_LIB_DIR} ${CTEST_LIB_DIR} ${SHARED_UTIL_LIB_DIR} $ENV{VCInstallDir}UnitTest/lib)
add_library(${whatIsBuilding}_lib STATIC
${${whatIsBuilding}_cpp_files}
${${whatIsBuilding}_h_files}
${${whatIsBuilding}_c_files}
)
#Add UnitTests to their own folder
set_target_properties(${whatIsBuilding}_lib
PROPERTIES
FOLDER "UnitTests")
target_include_directories(${whatIsBuilding}_lib PUBLIC ${sharedutil_include_directories})
target_compile_definitions(${whatIsBuilding}_lib PUBLIC -DUSE_CTEST)
target_link_libraries(${whatIsBuilding}_lib micromock_cpp_unittest ctest ${ARGN})
endfunction()
function(build_test_artifacts whatIsBuilding use_gballoc)
#the first argument is what is building
#the second argument is whether the tests should be build with gballoc #defines or not
#the following arguments are a list of libraries to link with
if(${use_gballoc})
add_definitions(-DGB_MEASURE_MEMORY_FOR_THIS -DGB_DEBUG_ALLOC)
else()
endif()
#setting #defines
if(WIN32)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
else()
endif()
#setting includes
set(sharedutil_include_directories ${MICROMOCK_INC_FOLDER} ${TESTRUNNERSWITCHER_INC_FOLDER} ${CTEST_INC_FOLDER} ${SAL_INC_FOLDER} ${SHARED_UTIL_INC_FOLDER} ${SHARED_UTIL_SRC_FOLDER} ../)
if(WIN32)
else()
include_directories(${sharedutil_include_directories})
endif()
#setting output type
if(WIN32)
#to disable running e2e or longhaul or unittests tests for windows, we build the the same thing as "static library" so it is not picked up by visual studio
if(
(("${whatIsBuilding}" MATCHES ".*e2e.*") AND NOT ${run_e2e_tests}) OR
(("${whatIsBuilding}" MATCHES ".*longhaul.*") AND NOT ${run_longhaul_tests}) OR
(("${whatIsBuilding}" MATCHES ".*unittests.*") AND ${skip_unittests})
)
windows_unittests_add_lib(${whatIsBuilding} ${ARGN})
else()
windows_unittests_add_exe(${whatIsBuilding} ${ARGN})
windows_unittests_add_dll(${whatIsBuilding} ${ARGN})
endif()
else()
if(
(("${whatIsBuilding}" MATCHES ".*e2e.*") AND NOT ${run_e2e_tests}) OR
(("${whatIsBuilding}" MATCHES ".*longhaul.*") AND NOT ${run_longhaul_tests}) OR
(("${whatIsBuilding}" MATCHES ".*unittests.*") AND ${skip_unittests})
)
windows_unittests_add_lib(${whatIsBuilding} ${ARGN})
else()
windows_unittests_add_exe(${whatIsBuilding} ${ARGN})
endif()
endif()
endfunction(build_test_artifacts)
option(memory_trace "set memory_trace to ON if memory usage is to be used, set to OFF to not use it" ON)
include_directories(inc ${SHARED_UTIL_INC_FOLDER})
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
if(${leak_detection})
add_definitions(-D_CRTDBG_MAP_ALLOC)
endif()
if(${memory_trace})
else()
add_definitions(-DDISABLE_MEMORY_TRACE)
endif()
if(WIN32)
include_directories($ENV{OpenSSLDir}/include)
endif()
if(wsio)
include_directories($ENV{WSDir}/lib $ENV{WSDir}/cmake)
endif()
set(uamqp_h_files
./inc/amqp_definitions.h
./inc/amqp_frame_codec.h
./inc/amqp_management.h
./inc/amqp_types.h
./inc/amqpalloc.h
./inc/amqpvalue.h
./inc/amqpvalue_to_string.h
./inc/cbs.h
./inc/connection.h
./inc/consolelogger.h
./inc/frame_codec.h
./inc/header_detect_io.h
./inc/link.h
./inc/logger.h
./inc/message.h
./inc/message_receiver.h
./inc/message_sender.h
./inc/messaging.h
./inc/sasl_anonymous.h
./inc/sasl_frame_codec.h
./inc/sasl_mechanism.h
./inc/sasl_mssbcbs.h
./inc/sasl_plain.h
./inc/saslclientio.h
./inc/session.h
./inc/socket_listener.h
)
set(uamqp_c_files
./src/amqp_definitions.c
./src/amqp_frame_codec.c
./src/amqp_management.c
./src/amqpalloc.c
./src/amqpvalue.c
./src/amqpvalue_to_string.c
./src/cbs.c
./src/connection.c
./src/consolelogger.c
./src/frame_codec.c
./src/header_detect_io.c
./src/link.c
./src/message.c
./src/message_receiver.c
./src/message_sender.c
./src/messaging.c
./src/sasl_anonymous.c
./src/sasl_frame_codec.c
./src/sasl_mechanism.c
./src/sasl_mssbcbs.c
./src/sasl_plain.c
./src/saslclientio.c
./src/session.c
)
if(wsio)
set(wsio_h_files
./inc/wsio.h
)
set(wsio_c_files
./src/wsio.c
)
else()
set(wsio_h_files
)
set(wsio_c_files
)
endif()
if(WIN32)
set(socketlistener_c_files
./src/socket_listener_win32.c
)
else()
set(socketlistener_c_files
)
endif()
add_library(uamqp
${uamqp_c_files}
${uamqp_h_files}
${wsio_c_files}
${wsio_h_files}
${socketlistener_c_files}
)
add_subdirectory(samples)
add_subdirectory(tests)

Просмотреть файл

@ -1,22 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30723.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "amqplib", "amqplib\amqplib.vcxproj", "{666A1F7D-0127-4C52-ACEC-16F3DF9E5CE2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{666A1F7D-0127-4C52-ACEC-16F3DF9E5CE2}.Debug|Win32.ActiveCfg = Debug|Win32
{666A1F7D-0127-4C52-ACEC-16F3DF9E5CE2}.Debug|Win32.Build.0 = Debug|Win32
{666A1F7D-0127-4C52-ACEC-16F3DF9E5CE2}.Release|Win32.ActiveCfg = Release|Win32
{666A1F7D-0127-4C52-ACEC-16F3DF9E5CE2}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Просмотреть файл

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{666A1F7D-0127-4C52-ACEC-16F3DF9E5CE2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>amqplib</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

Просмотреть файл

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
</Project>

@ -0,0 +1 @@
Subproject commit c6ed596ee8f468d8e1acaae050506c76b4b2c373

71
build_all/linux/build.sh Normal file
Просмотреть файл

@ -0,0 +1,71 @@
#!/bin/bash
#set -o pipefail
#
set -e
script_dir=$(cd "$(dirname "$0")" && pwd)
build_root=$(cd "${script_dir}/../.." && pwd)
run_unit_tests=ON
usage ()
{
echo "build.sh [options]"
echo "options"
echo " -cl, --compileoption <value> specify a compile option to be passed to gcc"
echo " Example: -cl -O1 -cl ..."
echo ""
exit 1
}
sync_dependencies ()
{
sharedutildir=/usr/include/azuresharedutil
# check to see if the file exists
if [ ! -d "$sharedutildir" ];
then
read -p "The required Azure Shared Utility does not exist would you like to install the component (y/n)?" input_var
# download the shared file
if [ "$input_var" == "y" ] || [ "$input_var" == "Y" ]
then
echo "preparing Azure Shared Utility"
else
exit 1
fi
rm -r -f ~/azure-c-shared-utility
git clone https://github.com/Azure/azure-c-shared-utility.git ~/azure-c-shared-utility
bash ~/azure-c-shared-utility/c/build_all/linux/build.sh -i
fi
}
process_args ()
{
save_next_arg=0
extracloptions=" "
for arg in $*
do
if [ $save_next_arg == 1 ]
then
# save arg to pass to gcc
extracloptions="$arg $extracloptions"
save_next_arg=0
else
case "$arg" in
"-cl" | "--compileoption" ) save_next_arg=1;;
* ) usage;;
esac
fi
done
}
process_args $*
rm -r -f ~/azure-amqp
mkdir ~/azure-amqp
pushd ~/azure-amqp
cmake -DcompileOption_C:STRING="$extracloptions" $build_root
make --jobs=$(nproc)
ctest -C "Debug" -V
popd

174
build_all/windows/build.cmd Normal file
Просмотреть файл

@ -0,0 +1,174 @@
@REM Copyright (c) Microsoft. All rights reserved.
@REM Licensed under the MIT license. See LICENSE file in the project root for full license information.
@setlocal EnableExtensions EnableDelayedExpansion
@echo off
set shared-util-repo=https://github.com/Azure/azure-c-shared-utility.git
set current-path=%~dp0
rem // remove trailing slash
set current-path=%current-path:~0,-1%
echo Current Path: %current-path%
set build-root=%current-path%\..\..
rem // resolve to fully qualified path
for %%i in ("%build-root%") do set build-root=%%~fi
set repo_root=%build-root%\..\..
rem // resolve to fully qualified path
for %%i in ("%repo_root%") do set repo_root=%%~fi
echo Repo Root: %build-root%
echo Repo Root: %repo_root%
rem -----------------------------------------------------------------------------
rem -- check prerequisites
rem -----------------------------------------------------------------------------
rem -- Check Shared-Library
if not defined SHARED_UTIL_LIB (
set SHARED_UTIL_LIB=%repo_root%\azure-c-shared-utility
)
if not exist %SHARED_UTIL_LIB% (
echo The Azure_Shared_Util does not exist, it shall be download and built
git clone %shared-util-repo%
call %SHARED_UTIL_LIB%\c\build_all\windows\build.cmd
)
rem -----------------------------------------------------------------------------
rem -- parse script arguments
rem -----------------------------------------------------------------------------
rem // default build options
set build-clean=0
set build-config=Debug
set build-platform=Win32
:args-loop
if "%1" equ "" goto args-done
if "%1" equ "-c" goto arg-build-clean
if "%1" equ "--clean" goto arg-build-clean
if "%1" equ "--config" goto arg-build-config
if "%1" equ "--platform" goto arg-build-platform
call :usage && exit /b 1
:arg-build-clean
set build-clean=1
goto args-continue
:arg-build-config
shift
if "%1" equ "" call :usage && exit /b 1
set build-config=%1
goto args-continue
:arg-build-platform
shift
if "%1" equ "" call :usage && exit /b 1
set build-platform=%1
goto args-continue
:args-continue
shift
goto args-loop
:args-done
rem -----------------------------------------------------------------------------
rem -- clean solutions
rem -----------------------------------------------------------------------------
if %build-clean%==1 (
rem -- call nuget restore "%build-root%\iothub_client\samples\iothub_client_sample_amqp\windows\iothub_client_sample_amqp.sln"
rem -- call :clean-a-solution "%build-root%\iothub_client\samples\iothub_client_sample_amqp\windows\iothub_client_sample_amqp.sln"
rem -- if not %errorlevel%==0 exit /b %errorlevel%
)
rem -----------------------------------------------------------------------------
rem -- build with CMAKE and run tests
rem -----------------------------------------------------------------------------
rmdir /s/q %USERPROFILE%\solution_azure_amqp
rem no error checking
mkdir %USERPROFILE%\solution_azure_amqp
rem no error checking
pushd %USERPROFILE%\solution_azure_amqp
cmake %build-root%
if not %errorlevel%==0 exit /b %errorlevel%
msbuild /m uamqp.sln
if not %errorlevel%==0 exit /b %errorlevel%
ctest -C "debug" -V
if not %errorlevel%==0 exit /b %errorlevel%
popd
goto :eof
rem -----------------------------------------------------------------------------
rem -- subroutines
rem -----------------------------------------------------------------------------
:clean-a-solution
call :_run-msbuild "Clean" %1 %2 %3
goto :eof
:build-a-solution
call :_run-msbuild "Build" %1 %2 %3
goto :eof
:run-unit-tests
call :_run-tests %1 "UnitTests"
goto :eof
:usage
echo build.cmd [options]
echo options:
echo -c, --clean delete artifacts from previous build before building
echo --config ^<value^> [Debug] build configuration (e.g. Debug, Release)
echo --platform ^<value^> [Win32] build platform (e.g. Win32, x64, ...)
goto :eof
rem -----------------------------------------------------------------------------
rem -- helper subroutines
rem -----------------------------------------------------------------------------
:_run-msbuild
rem // optionally override configuration|platform
setlocal EnableExtensions
set build-target=
if "%~1" neq "Build" set "build-target=/t:%~1"
if "%~3" neq "" set build-config=%~3
if "%~4" neq "" set build-platform=%~4
msbuild /m %build-target% "/p:Configuration=%build-config%;Platform=%build-platform%" %2
if not %errorlevel%==0 exit /b %errorlevel%
goto :eof
:_run-tests
rem // discover tests
set test-dlls-list=
set test-dlls-path=%build-root%\%~1\build\windows\%build-platform%\%build-config%
for /f %%i in ('dir /b %test-dlls-path%\*%~2*.dll') do set test-dlls-list="%test-dlls-path%\%%i" !test-dlls-list!
if "%test-dlls-list%" equ "" (
echo No unit tests found in %test-dlls-path%
exit /b 1
)
rem // run tests
echo Test DLLs: %test-dlls-list%
echo.
vstest.console.exe %test-dlls-list%
if not %errorlevel%==0 exit /b %errorlevel%
goto :eof
echo done

25
contribute.md Normal file
Просмотреть файл

@ -0,0 +1,25 @@
## What to contribute
There are many ways that you can contribute to the uAMQP project:
* Submit a bug
* Submit a code fix for a bug
* Submit code to add a new platform/language support to the project, or modify existing code
* Submit additions or modifications to the documentation
* Submit a feature request
## Contributing Code
To contribute code you need to issue a Pull Request against the master branch. All code submissions will be reviewed and tested, and those that meet a high bar for both quality and design/roadmap appropriateness will be merged into the source.
You must sign a [Contribution License Agreement](https://cla.microsoft.com/) ([CLA](https://cla.microsoft.com/)) before submitting a Pull Request. To complete the CLA, you will need to submit the request via the form and then electronically sign the CLA when you receive the email containing the link to the document.
## Big contributions
If your contribution is significantly big it is better to first check with the project developers in order to make sure the change aligns with the long term plans. This can be done simply by submitting a question via the GitHub Issues section.
## Things to keep in mind when contributing
Some guidance for when you make a contribution:
* Add/update the Visio design diagram when required by your change
* Add/update module requirements as required by your change
* Add/update unit tests and code as required by your change
* Make sure you run all the unit tests on the affected platform(s). If the change is in common code, generally running on one platform would be acceptable
* Run end-to-end tests or simple sample code to make sure the lib works in an end-to-end scenario.

Двоичные данные
design/AMQPLib.vsdx Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,129 @@
#amqp_frame_codec requirements
##Overview
amqp_frame_codec is module that encodes/decodes AMQP frames per the AMQP ISO.
##Exposed API
```C
#define AMQP_OPEN (uint64_t)0x10
#define AMQP_BEGIN (uint64_t)0x11
#define AMQP_ATTACH (uint64_t)0x12
#define AMQP_FLOW (uint64_t)0x13
#define AMQP_TRANSFER (uint64_t)0x14
#define AMQP_DISPOSITION (uint64_t)0x15
#define AMQP_DETACH (uint64_t)0x16
#define AMQP_END (uint64_t)0x17
#define AMQP_CLOSE (uint64_t)0x18
typedef void* AMQP_FRAME_CODEC_HANDLE;
typedef void(*AMQP_EMPTY_FRAME_RECEIVED_CALLBACK)(void* context, uint16_t channel);
typedef void(*AMQP_FRAME_RECEIVED_CALLBACK)(void* context, uint16_t channel, AMQP_VALUE performative, const unsigned char* payload_bytes, uint32_t frame_payload_size);
typedef void(*AMQP_FRAME_CODEC_ERROR_CALLBACK)(void* context);
extern AMQP_FRAME_CODEC_HANDLE amqp_frame_codec_create(FRAME_CODEC_HANDLE frame_codec, AMQP_FRAME_RECEIVED_CALLBACK frame_received_callback, AMQP_EMPTY_FRAME_RECEIVED_CALLBACK empty_frame_received_callback, AMQP_FRAME_CODEC_ERROR_CALLBACK amqp_frame_codec_error_callback, void* callback_context);
extern void amqp_frame_codec_destroy(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec);
extern int amqp_frame_codec_begin_encode_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel, const AMQP_VALUE performative, uint32_t payload_size);
extern int amqp_frame_codec_encode_payload_bytes(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, const unsigned char* bytes, uint32_t count);
extern int amqp_frame_codec_encode_empty_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel);
```
###amqp_frame_codec_create
```C
extern AMQP_FRAME_CODEC_HANDLE amqp_frame_codec_create(FRAME_CODEC_HANDLE frame_codec, AMQP_FRAME_RECEIVED_CALLBACK frame_received_callback, AMQP_EMPTY_FRAME_RECEIVED_CALLBACK empty_frame_received_callback, AMQP_FRAME_CODEC_ERROR_CALLBACK amqp_frame_codec_error_callback, void* callback_context);
```
**SRS_AMQP_FRAME_CODEC_01_011: [**amqp_frame_codec_create shall create an instance of an amqp_frame_codec and return a non-NULL handle to it.**]**
**SRS_AMQP_FRAME_CODEC_01_012: [**If any of the arguments frame_codec, frame_received_callback, amqp_frame_codec_error_callback or empty_frame_received_callback is NULL, amqp_frame_codec_create shall return NULL.**]**
**SRS_AMQP_FRAME_CODEC_01_013: [**amqp_frame_codec_create shall subscribe for AMQP frames with the given frame_codec.**]**
**SRS_AMQP_FRAME_CODEC_01_014: [**If subscribing for AMQP frames fails, amqp_frame_codec_create shall fail and return NULL.**]**
**SRS_AMQP_FRAME_CODEC_01_018: [**amqp_frame_codec_create shall create a decoder to be used for decoding AMQP values.**]**
**SRS_AMQP_FRAME_CODEC_01_019: [**If creating the decoder fails, amqp_frame_codec_create shall fail and return NULL.**]**
**SRS_AMQP_FRAME_CODEC_01_020: [**If allocating memory for the new amqp_frame_codec fails, then amqp_frame_codec_create shall fail and return NULL.**]**
###amqp_frame_codec_destroy
```C
extern void amqp_frame_codec_destroy(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec);
```
**SRS_AMQP_FRAME_CODEC_01_015: [**amqp_frame_codec_destroy shall free all resources associated with the amqp_frame_codec instance.**]**
**SRS_AMQP_FRAME_CODEC_01_016: [**If amqp_frame_codec is NULL, amqp_frame_codec_destroy shall do nothing.**]**
**SRS_AMQP_FRAME_CODEC_01_017: [**amqp_frame_codec_destroy shall unsubscribe from receiving AMQP frames from the frame_codec that was passed to amqp_frame_codec_create.**]**
**SRS_AMQP_FRAME_CODEC_01_021: [**The decoder created in amqp_frame_codec_create shall be destroyed by amqp_frame_codec_destroy.**]**
###amqp_frame_codec_encode_frame
```C
extern int amqp_frame_codec_encode_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel, const AMQP_VALUE performative, PAYLOAD* payloads, size_t payload_count, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context);
```
**SRS_AMQP_FRAME_CODEC_01_022: [**amqp_frame_codec_encode_frame shall encode the frame header and AMQP performative in an AMQP frame and on success it shall return 0.**]**
**SRS_AMQP_FRAME_CODEC_01_024: [**If frame_codec, performative or on_bytes_encoded is NULL, amqp_frame_codec_encode_frame shall fail and return a non-zero value.**]**
**SRS_AMQP_FRAME_CODEC_01_025: [**amqp_frame_codec_encode_frame shall encode the frame header by using frame_codec_encode_frame.**]**
**SRS_AMQP_FRAME_CODEC_01_026: [**The payload frame size shall be computed based on the encoded size of the performative and its fields plus the sum of the payload sizes passed via the payloads argument.**]**
**SRS_AMQP_FRAME_CODEC_01_027: [**The encoded size of the performative and its fields shall be obtained by calling amqpvalue_get_encoded_size.**]**
**SRS_AMQP_FRAME_CODEC_01_029: [**If any error occurs during encoding, amqp_frame_codec_encode_frame shall fail and return a non-zero value.**]**
**SRS_AMQP_FRAME_CODEC_01_030: [**Encoding of the AMQP performative and its fields shall be done by calling amqpvalue_encode.**]**
**SRS_AMQP_FRAME_CODEC_01_028: [**The encode result for the performative shall be placed in a PAYLOAD structure.**]**
**SRS_AMQP_FRAME_CODEC_01_070: [**The payloads argument for frame_codec_encode_frame shall be made of the payload for the encoded performative and the payloads passed to amqp_frame_codec_encode_frame.**]**
###amqp_frame_codec_encode_empty_frame
```C
extern int amqp_frame_codec_encode_empty_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel);
```
**SRS_AMQP_FRAME_CODEC_01_042: [**amqp_frame_codec_encode_empty_frame shall encode a frame with no payload.**]**
**SRS_AMQP_FRAME_CODEC_01_043: [**On success, amqp_frame_codec_encode_empty_frame shall return 0.**]**
**SRS_AMQP_FRAME_CODEC_01_044: [**amqp_frame_codec_encode_empty_frame shall use frame_codec_encode_frame to encode the frame.**]**
**SRS_AMQP_FRAME_CODEC_01_045: [**If amqp_frame_codec is NULL, amqp_frame_codec_encode_empty_frame shall fail and return a non-zero value.**]**
**SRS_AMQP_FRAME_CODEC_01_046: [**If encoding fails in any way, amqp_frame_codec_encode_empty_frame shall fail and return a non-zero value.**]**
###Receive frames
**SRS_AMQP_FRAME_CODEC_01_048: [**When a frame header is received from frame_codec and the frame payload size is 0, empty_frame_received_callback shall be invoked, while passing the channel number as argument.**]**
**SRS_AMQP_FRAME_CODEC_01_049: [**If not enough type specific bytes are received to decode the channel number, the decoding shall stop with an error.**]**
**SRS_AMQP_FRAME_CODEC_01_050: [**All subsequent decoding shall fail and no AMQP frames shall be indicated from that point on to the consumers of amqp_frame_codec.**]**
**SRS_AMQP_FRAME_CODEC_01_051: [**If the frame payload is greater than 0, amqp_frame_codec shall decode the performative as a described AMQP type.**]**
**SRS_AMQP_FRAME_CODEC_01_052: [**Decoding the performative shall be done by feeding the bytes to the decoder create in amqp_frame_codec_create.**]**
**SRS_AMQP_FRAME_CODEC_01_067: [**When the performative is decoded, the rest of the frame_bytes shall not be given to the AMQP decoder, but they shall be buffered so that later they are given to the frame_received callback.**]**
**SRS_AMQP_FRAME_CODEC_01_054: [**Once the performative is decoded and all frame payload bytes are received, the callback frame_received_callback shall be called.**]**
**SRS_AMQP_FRAME_CODEC_01_055: [**The decoded channel and performative shall be passed to frame_received_callback.**]**
**SRS_AMQP_FRAME_CODEC_01_056: [**The AMQP frame payload size passed to frame_received_callback shall be computed from the frame payload size received from frame_codec and substracting the performative size.**]**
**SRS_AMQP_FRAME_CODEC_01_068: [**A pointer to all the payload bytes shall also be passed to frame_received_callback.**]**
**SRS_AMQP_FRAME_CODEC_01_060: [**If any error occurs while decoding a frame, the decoder shall switch to an error state where decoding shall not be possible anymore.**]**
**SRS_AMQP_FRAME_CODEC_01_069: [**If any error occurs while decoding a frame, the decoder shall indicate the error by calling the amqp_frame_codec_error_callback and passing to it the callback context argument that was given in amqp_frame_codec_create.**]**
###ISO section (receive)
2.3.2 AMQP Frames
**SRS_AMQP_FRAME_CODEC_01_001: [**Bytes 6 and 7 of an AMQP frame contain the channel number **]** (see section 2.1).
**SRS_AMQP_FRAME_CODEC_01_002: [**The frame body is defined as a performative followed by an opaque payload.**]**
**SRS_AMQP_FRAME_CODEC_01_003: [**The performative MUST be one of those defined in section 2.7 and is encoded as a described type in the AMQP type system.**]**
**SRS_AMQP_FRAME_CODEC_01_004: [**The remaining bytes in the frame body form the payload for that frame.**]** The presence and format of the payload is defined by the semantics of the given performative.
...
Figure 2.16: AMQP Frame Layout
**SRS_AMQP_FRAME_CODEC_01_007: [**An AMQP frame with no body MAY be used to generate artificial traffic as needed to satisfy any negotiated idle timeout interval **]** (see subsection 2.4.5).
###ISO section (send)
2.3.2 AMQP Frames
**SRS_AMQP_FRAME_CODEC_01_005: [**Bytes 6 and 7 of an AMQP frame contain the channel number **]** (see section 2.1).
**SRS_AMQP_FRAME_CODEC_01_006: [**The frame body is defined as a performative followed by an opaque payload.**]**
**SRS_AMQP_FRAME_CODEC_01_008: [**The performative MUST be one of those defined in section 2.7 and is encoded as a described type in the AMQP type system.**]**
**SRS_AMQP_FRAME_CODEC_01_009: [**The remaining bytes in the frame body form the payload for that frame.**]** The presence and format of the payload is defined by the semantics of the given performative.
...
Figure 2.16: AMQP Frame Layout
**SRS_AMQP_FRAME_CODEC_01_010: [**An AMQP frame with no body MAY be used to generate artificial traffic as needed to satisfy any negotiated idle timeout interval **]** (see subsection 2.4.5).

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,570 @@
#connection requirements
##Overview
connection is module that implements the connection layer in the AMQP ISO.
##Exposed API
```C
typedef void* CONNECTION_HANDLE;
typedef enum CONNECTION_STATE_TAG
{
CONNECTION_STATE_START,
CONNECTION_STATE_HDR_RCVD,
CONNECTION_STATE_HDR_SENT,
CONNECTION_STATE_HDR_EXCH,
CONNECTION_STATE_OPEN_PIPE,
CONNECTION_STATE_OC_PIPE,
CONNECTION_STATE_OPEN_RCVD,
CONNECTION_STATE_OPEN_SENT,
CONNECTION_STATE_CLOSE_PIPE,
CONNECTION_STATE_OPENED,
CONNECTION_STATE_CLOSE_RCVD,
CONNECTION_STATE_CLOSE_SENT,
CONNECTION_STATE_DISCARDING,
CONNECTION_STATE_END
} CONNECTION_STATE;
typedef void(*ON_ENDPOINT_FRAME_RECEIVED)(void* context, AMQP_VALUE performative, uint32_t frame_payload_size, const unsigned char* payload_bytes);
typedef void(*ON_CONNECTION_STATE_CHANGED)(void* context, CONNECTION_STATE new_connection_state, CONNECTION_STATE previous_connection_state);
extern CONNECTION_HANDLE connection_create(XIO_HANDLE xio, const char* hostname, const char* container_id);
extern int connection_set_max_frame_size(CONNECTION_HANDLE connection, uint32_t max_frame_size);
extern int connection_get_max_frame_size(CONNECTION_HANDLE connection, uint32_t* max_frame_size);
extern int connection_set_channel_max(CONNECTION_HANDLE connection, uint16_t channel_max);
extern int connection_get_channel_max(CONNECTION_HANDLE connection, uint16_t* channel_max);
extern int connection_set_idle_timeout(CONNECTION_HANDLE connection, milliseconds idle_timeout);
extern int connection_get_idle_timeout(CONNECTION_HANDLE connection, milliseconds* idle_timeout);
extern int connection_get_remote_max_frame_size(CONNECTION_HANDLE connection, uint32_t* remote_max_frame_size);
extern void connection_destroy(CONNECTION_HANDLE connection);
extern void connection_dowork(CONNECTION_HANDLE connection);
extern ENDPOINT_HANDLE connection_create_endpoint(CONNECTION_HANDLE connection, ON_ENDPOINT_FRAME_RECEIVED on_frame_received, ON_CONNECTION_STATE_CHANGED on_connection_state_changed, void* context);
extern void connection_destroy_endpoint(ENDPOINT_HANDLE endpoint);
extern int connection_encode_frame(ENDPOINT_HANDLE endpoint, const AMQP_VALUE performative, PAYLOAD* payloads, size_t payload_count);
```
###connection_create
```C
extern CONNECTION_HANDLE connection_create(XIO_HANDLE xio, const char* container_id);
```
**SRS_CONNECTION_01_001: [**connection_create shall open a new connection to a specified host/port.**]**
**SRS_CONNECTION_01_071: [**If xio or container_id is NULL, connection_create shall return NULL.**]**
**SRS_CONNECTION_01_082: [**connection_create shall allocate a new frame_codec instance to be used for frame encoding/decoding.**]**
**SRS_CONNECTION_01_083: [**If frame_codec_create fails then connection_create shall return NULL.**]**
**SRS_CONNECTION_01_107: [**connection_create shall create an amqp_frame_codec instance by calling amqp_frame_codec_create.**]**
**SRS_CONNECTION_01_108: [**If amqp_frame_codec_create fails, connection_create shall return NULL.**]**
**SRS_CONNECTION_01_072: [**When connection_create succeeds, the state of the connection shall be CONNECTION_STATE_START.**]**
**SRS_CONNECTION_01_081: [**If allocating the memory for the connection fails then connection_create shall return NULL.**]**
###connection_set_max_frame_size
```C
extern int connection_set_max_frame_size(CONNECTION_HANDLE connection, uint32_t max_frame_size);
```
**SRS_CONNECTION_01_148: [**connection_set_max_frame_size shall set the max_frame_size associated with a connection.**]**
**SRS_CONNECTION_01_149: [**On success connection_set_max_frame_size shall return 0.**]**
**SRS_CONNECTION_01_163: [**If connection is NULL, connection_set_max_frame_size shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_150: [**If the max_frame_size is invalid then connection_set_max_frame_size shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_152: [**If frame_codec_set_max_frame_size fails then connection_set_max_frame_size shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_157: [**If connection_set_max_frame_size is called after the initial Open frame has been sent, it shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_164: [**If connection_set_max_frame_size fails, the previous max_frame_size setting shall be retained.**]**
###connection_get_max_frame_size
```C
int connection_get_max_frame_size(CONNECTION_HANDLE connection, uint32_t* max_frame_size);
```
**SRS_CONNECTION_01_168: [**connection_get_max_frame_size shall return in the max_frame_size argument the current max frame size setting.**]**
**SRS_CONNECTION_01_169: [**On success, connection_get_max_frame_size shall return 0.**]**
**SRS_CONNECTION_01_170: [**If connection or max_frame_size is NULL, connection_get_max_frame_size shall fail and return a non-zero value.**]**
###connection_set_channel_max
```C
extern int connection_set_channel_max(CONNECTION_HANDLE connection, uint16_t channel_max);
```
**SRS_CONNECTION_01_153: [**connection_set_channel_max shall set the channel_max associated with a connection.**]**
**SRS_CONNECTION_01_154: [**On success connection_set_channel_max shall return 0.**]**
**SRS_CONNECTION_01_181: [**If connection is NULL then connection_set_channel_max shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_156: [**If connection_set_channel_max is called after the initial Open frame has been sent, it shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_165: [**If connection_set_channel_max fails, the previous channel_max setting shall be retained.**]**
**SRS_CONNECTION_01_257: [**connection_set_channel_max shall fail if channel_max is higher than the outgoing channel number of any already created endpoints.**]**
###connection_get_channel_max
```C
extern int connection_get_channel_max(CONNECTION_HANDLE connection, uint16_t* channel_max);
```
**SRS_CONNECTION_01_182: [**connection_get_channel_max shall return in the channel_max argument the current channel_max setting.**]**
**SRS_CONNECTION_01_183: [**On success, connection_get_channel_max shall return 0.**]**
**SRS_CONNECTION_01_184: [**If connection or channel_max is NULL, connection_get_channel_max shall fail and return a non-zero value.**]**
###connection_set_idle_timeout
```C
extern int connection_set_idle_timeout(CONNECTION_HANDLE connection, milliseconds idle_timeout);
```
**SRS_CONNECTION_01_159: [**connection_set_idle_timeout shall set the idle_timeout associated with a connection.**]**
**SRS_CONNECTION_01_160: [**On success connection_set_idle_timeout shall return 0.**]**
**SRS_CONNECTION_01_191: [**If connection is NULL, connection_set_idle_timeout shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_158: [**If connection_set_idle_timeout is called after the initial Open frame has been sent, it shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_166: [**If connection_set_idle_timeout fails, the previous idle_timeout setting shall be retained.**]**
###connection_get_idle_timeout
```C
extern int connection_get_idle_timeout(CONNECTION_HANDLE connection, milliseconds* idle_timeout);
```
**SRS_CONNECTION_01_188: [**connection_get_idle_timeout shall return in the idle_timeout argument the current idle_timeout setting.**]**
**SRS_CONNECTION_01_189: [**On success, connection_get_idle_timeout shall return 0.**]**
**SRS_CONNECTION_01_190: [**If connection or idle_timeout is NULL, connection_get_idle_timeout shall fail and return a non-zero value.**]**
###connection_get_remote_max_frame_size
```C
extern int connection_get_remote_max_frame_size(CONNECTION_HANDLE connection, uint32_t* remote_max_frame_size);
```
###connection_destroy
```C
extern void connection_destroy(CONNECTION_HANDLE handle);
```
**SRS_CONNECTION_01_073: [**connection_destroy shall free all resources associated with a connection.**]**
**SRS_CONNECTION_01_074: [**connection_destroy shall close the socket connection.**]**
**SRS_CONNECTION_01_075: [**If an Open frame has been sent then a Close frame shall be sent before closing the socket.**]**
**SRS_CONNECTION_01_079: [**If handle is NULL, connection_destroy shall do nothing.**]**
###connection_dowork
```C
extern void connection_dowork(CONNECTION_HANDLE connection);
```
**SRS_CONNECTION_01_076: [**connection_dowork shall schedule the underlying IO interface to do its work by calling xio_dowork.**]**
**SRS_CONNECTION_01_078: [**If handle is NULL, connection_dowork shall do nothing.**]**
**SRS_CONNECTION_01_084: [**The connection state machine implementing the protocol requirements shall be run as part of connection_dowork.**]**
**SRS_CONNECTION_01_202: [**If the io notifies the connection instance of an IO_STATE_ERROR state the connection shall be closed and the state set to END.**]**
**SRS_CONNECTION_01_104: [**Sending the protocol header shall be done by using xio_send.**]**
**SRS_CONNECTION_01_106: [**When sending the protocol header fails, the connection shall be immediately closed.**]**
**SRS_CONNECTION_01_151: [**The connection max_frame_size setting shall be passed down to the frame_codec when the Open frame is sent.**]**
**SRS_CONNECTION_01_207: [**If frame_codec_set_max_frame_size fails the connection shall be closed and the state set to END.**]**
###connection_create_endpoint
```C
extern ENDPOINT_HANDLE connection_create_endpoint(CONNECTION_HANDLE connection, ON_ENDPOINT_FRAME_RECEIVED on_endpoint_frame_received, ON_CONNECTION_STATE_CHANGED on_connection_state_changed, void* context);
```
**SRS_CONNECTION_01_112: [**connection_create_endpoint shall create a new endpoint that can be used by a session.**]**
**SRS_CONNECTION_01_127: [**On success, connection_create_endpoint shall return a non-NULL handle to the newly created endpoint.**]**
**SRS_CONNECTION_01_113: [**If connection, on_endpoint_frame_received or on_connection_state_changed is NULL, connection_create_endpoint shall fail and return NULL.**]**
**SRS_CONNECTION_01_193: [**The context argument shall be allowed to be NULL.**]**
**SRS_CONNECTION_01_115: [**If no more endpoints can be created due to all channels being used, connection_create_endpoint shall fail and return NULL.**]**
**SRS_CONNECTION_01_128: [**The lowest number outgoing channel shall be associated with the newly created endpoint.**]**
**SRS_CONNECTION_01_196: [**If memory cannot be allocated for the new endpoint, connection_create_endpoint shall fail and return NULL.**]**
**SRS_CONNECTION_01_197: [**The newly created endpoint shall be added to the endpoints list, so that it can be tracked.**]**
**SRS_CONNECTION_01_198: [**If adding the endpoint to the endpoints list tracked by the connection fails, connection_create_endpoint shall fail and return NULL.**]**
###connection_destroy_endpoint
```C
extern void connection_destroy_endpoint(ENDPOINT_HANDLE endpoint);
```
**SRS_CONNECTION_01_129: [**connection_destroy_endpoint shall free all resources associated with an endpoint created by connection_create_endpoint.**]**
**SRS_CONNECTION_01_130: [**The outgoing channel associated with the endpoint shall be released by removing the endpoint from the endpoint list.**]**
**SRS_CONNECTION_01_131: [**Any incoming channel number associated with the endpoint shall be released.**]**
**SRS_CONNECTION_01_199: [**If endpoint is NULL, connection_destroy_endpoint shall do nothing.**]**
###connection_encode_frame
```C
extern int connection_encode_frame(ENDPOINT_HANDLE endpoint, const AMQP_VALUE performative, PAYLOAD* payloads, size_t payload_count);
```
**SRS_CONNECTION_01_247: [**connection_encode_frame shall send a frame for a certain endpoint.**]**
**SRS_CONNECTION_01_248: [**On success it shall return 0.**]**
**SRS_CONNECTION_01_249: [**If endpoint or performative are NULL, connection_encode_frame shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_250: [**connection_encode_frame shall initiate the frame send by calling amqp_frame_codec_begin_encode_frame.**]**
**SRS_CONNECTION_01_251: [**The channel number passed to amqp_frame_codec_begin_encode_frame shall be the outgoing channel number associated with the endpoint by connection_create_endpoint.**]**
**SRS_CONNECTION_01_252: [**The performative passed to amqp_frame_codec_begin_encode_frame shall be the performative argument of connection_encode_frame.**]**
**SRS_CONNECTION_01_255: [**The payload size shall be computed based on all the payload chunks passed as argument in payloads.**]**
**SRS_CONNECTION_01_253: [**If amqp_frame_codec_begin_encode_frame or amqp_frame_codec_encode_payload_bytes fails, then connection_encode_frame shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_254: [**If connection_encode_frame is called before the connection is in the OPENED state, connection_encode_frame shall fail and return a non-zero value.**]**
**SRS_CONNECTION_01_256: [**Each payload passed in the payloads array shall be passed to amqp_frame_codec by calling amqp_frame_codec_encode_payload_bytes.**]**
###on_connection_state_changed
**SRS_CONNECTION_01_258: [**on_connection_state_changed shall be invoked whenever the connection state changes.**]**
**SRS_CONNECTION_01_260: [**Each endpoint's on_connection_state_changed shall be called.**]**
**SRS_CONNECTION_01_259: [**As context, the callback_context passed in connection_create_endpoint shall be given.**]**
##Frame construction
###Open frame construction
**SRS_CONNECTION_01_134: [**The container id field shall be filled with the container id specified in connection_create.**]**
**SRS_CONNECTION_01_135: [**If hostname has been specified by a call to connection_set_hostname, then that value shall be stamped in the open frame.**]**
**SRS_CONNECTION_01_136: [**If no hostname value has been specified, no value shall be stamped in the open frame (no call to open_set_hostname shall be made).**]**
**SRS_CONNECTION_01_137: [**If max_frame_size has been specified by a call to connection_set_max_frame, then that value shall be stamped in the open frame.**]**
**SRS_CONNECTION_01_139: [**If channel_max has been specified by a call to connection_set_channel_max, then that value shall be stamped in the open frame.**]**
**SRS_CONNECTION_01_141: [**If idle_timeout has been specified by a call to connection_set_idle_timeout, then that value shall be stamped in the open frame.**]**
**SRS_CONNECTION_01_142: [**If no idle_timeout value has been specified, no value shall be stamped in the open frame (no call to open_set_idle_time_out shall be made).**]**
**SRS_CONNECTION_01_205: [**Sending the AMQP OPEN frame shall be done by calling amqp_frame_codec_begin_encode_frame with channel number 0, the actual performative payload and 0 as payload_size.**]**
**SRS_CONNECTION_01_206: [**If sending the frame fails, the connection shall be closed and state set to END.**]**
**SRS_CONNECTION_01_208: [**If the open frame cannot be constructed, the connection shall be closed and set to the END state.**]**
###Close frame construction
**SRS_CONNECTION_01_217: [**The CLOSE frame shall be constructed by using close_create.**]**
**SRS_CONNECTION_01_215: [**Sending the AMQP CLOSE frame shall be done by calling amqp_frame_codec_begin_encode_frame with channel number 0, the actual performative payload and 0 as payload_size.**]**
**SRS_CONNECTION_01_214: [**If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.**]**
##Frame reception
**SRS_CONNECTION_01_212: [**After the initial handshake has been done all bytes received from the io instance shall be passed to the frame_codec for decoding by calling frame_codec_receive_bytes.**]**
**SRS_CONNECTION_01_213: [**When passing the bytes to frame_codec fails, a CLOSE frame shall be sent and the state shall be set to DISCARDING.**]**
**SRS_CONNECTION_01_218: [**The error amqp:internal-error shall be set in the error.condition field of the CLOSE frame.**]**
**SRS_CONNECTION_01_219: [**The error description shall be set to an implementation defined string.**]**
**SRS_CONNECTION_01_223: [**If the amqp_frame_received_callback is called with a NULL performative then the connection shall be closed with the error condition amqp:internal-error and an implementation defined error description.**]**
**SRS_CONNECTION_01_241: [**The connection module shall accept OPEN frames even if they have extra payload bytes besides the Open performative.**]**
**SRS_CONNECTION_01_242: [**The connection module shall accept CLOSE frames even if they have extra payload bytes besides the Close performative.**]**
###Open frame reception
**SRS_CONNECTION_01_143: [**If any of the values in the received open frame are invalid then the connection shall be closed.**]**
**SRS_CONNECTION_01_220: [**The error amqp:invalid-field shall be set in the error.condition field of the CLOSE frame.**]**
**SRS_CONNECTION_01_221: [**The error description shall be set to an implementation defined string.**]**
**SRS_CONNECTION_01_222: [**If an Open frame is received in a manner violating the ISO specification, the connection shall be closed with condition amqp:not-allowed and description being an implementation defined string.**]**
**SRS_CONNECTION_01_239: [**If an Open frame is received in the Opened state the connection shall be closed with condition amqp:illegal-state and description being an implementation defined string.**]**
###Begin frame reception
**SRS_CONNECTION_01_144: [**When a begin frame is received, the connection shall only look at the remote_channel field and if the remote channel field matches one of the outgoing channels of an already created endpoint, then the channel number on which the Begin frame was received shall be assigned as incoming channel number for the endpoint.**]**
**SRS_CONNECTION_01_145: [**If the endpoint already has a channel number assigned then this shall be considered a protocol violation and the connection shall be closed.**]**
**SRS_CONNECTION_01_146: [**If no endpoint can be found for the specified remote channel, this shall be considered a protocol violation and the connection shall be closed.**]**
Not implemented: outgoing_locales, incoming_locales, offered_capabilities, desired_capabilities, properties.
##Connection ISO section
2.2 Version Negotiation
**SRS_CONNECTION_01_086: [**Prior to sending any frames on a connection, each peer MUST start by sending a protocol header that indicates the protocol version used on the connection.**]**
**SRS_CONNECTION_01_087: [**The protocol header consists of the upper case ASCII letters "AMQP" followed by a protocol id of zero, followed by three unsigned bytes representing the major, minor, and revision of the protocol version (currently 1 (MAJOR), 0 (MINOR), 0 (REVISION)). In total this is an 8-octet sequence**]**:
...
Figure 2.11: Protocol Header Layout
**SRS_CONNECTION_01_088: [**Any data appearing beyond the protocol header MUST match the version indicated by the protocol header.**]**
**SRS_CONNECTION_01_089: [**If the incoming and outgoing protocol headers do not match, both peers MUST close their outgoing stream**]**
**SRS_CONNECTION_01_090: [**and SHOULD read the incoming stream until it is terminated.**]**
**SRS_CONNECTION_01_091: [**The AMQP peer which acted in the role of the TCP client (i.e. the peer that actively opened the connection) MUST immediately send its outgoing protocol header on establishment of the TCP connection.**]**
**SRS_CONNECTION_01_092: [**The AMQP peer which acted in the role of the TCP server MAY elect to wait until receiving the incoming protocol header before sending its own outgoing protocol header. This permits a multi protocol server implementation to choose the correct protocol version to fit each client.**]**
Two AMQP peers agree on a protocol version as follows (where the words "client" and "server" refer to the roles being played by the peers at the TCP connection level):
**SRS_CONNECTION_01_093: [**_ When the client opens a new socket connection to a server, it MUST send a protocol header with the client's preferred protocol version.**]**
**SRS_CONNECTION_01_094: [**_ If the requested protocol version is supported, the server MUST send its own protocol header with the requested version to the socket, and then proceed according to the protocol definition.**]**
**SRS_CONNECTION_01_095: [**_ If the requested protocol version is not supported, the server MUST send a protocol header with a supported protocol version and then close the socket.**]**
**SRS_CONNECTION_01_096: [**_ When choosing a protocol version to respond with, the server SHOULD choose the highest supported version that is less than or equal to the requested version.**]**
**SRS_CONNECTION_01_097: [**If no such version exists, the server SHOULD respond with the highest supported version.**]**
**SRS_CONNECTION_01_098: [**_ If the server cannot parse the protocol header, the server MUST send a valid protocol header with a supported protocol version and then close the socket.**]**
**SRS_CONNECTION_01_099: [**_ Note that if the server only supports a single protocol version, it is consistent with the above rules for the server to send its protocol header prior to receiving anything from the client and to subsequently close the socket if the client's protocol header does not match the server's.**]**
**SRS_CONNECTION_01_100: [**Based on this behavior a client can discover which protocol versions a server supports by attempting to connect with its highest supported version and reconnecting with a version less than or equal to the version received back from the server.**]**
...
Figure 2.12: Version Negotiation Examples
Please note that the above examples use the literal notation defined in RFC 2234 [RFC2234] for non alphanumeric values.
**SRS_CONNECTION_01_101: [**The protocol id is not a part of the protocol version and thus the rule above regarding the highest supported version does not apply.**]**
**SRS_CONNECTION_01_102: [**A client might request use of a protocol id that is unacceptable to a server - for example, it might request a raw AMQP connection when the server is configured to require a TLS or SASL security layer (See Part 5: section 5.1). In this case, the server MUST send a protocol header with an acceptable protocol id (and version) and then close the socket.**]**
**SRS_CONNECTION_01_103: [**It MAY choose any protocol id.**]**
...
Figure 2.13: Protocol ID Rejection Example
2.4 Connections
**SRS_CONNECTION_01_061: [**AMQP connections are divided into a number of unidirectional channels.**]**
**SRS_CONNECTION_01_062: [**A connection endpoint contains two kinds of channel endpoints: incoming and outgoing.**]**
**SRS_CONNECTION_01_063: [**A connection endpoint maps incoming frames other than open and close to an incoming channel endpoint based on the incoming channel number, as well as relaying frames produced by outgoing channel endpoints, marking them with the associated outgoing channel number before sending them.**]**
**SRS_CONNECTION_01_058: [**This requires connection endpoints to contain two mappings.**]**
**SRS_CONNECTION_01_059: [**One from incoming channel number to incoming channel endpoint**]** ,
**SRS_CONNECTION_01_060: [**and one from outgoing channel endpoint, to outgoing channel number.**]**
...
Figure 2.17: Unidirectional Channel Multiplexing
**SRS_CONNECTION_01_064: [**Channels are unidirectional, and thus at each connection endpoint the incoming and outgoing channels are completely distinct.**]**
**SRS_CONNECTION_01_065: [**Channel numbers are scoped relative to direction, thus there is no causal relation between incoming and outgoing channels that happen to be identified by the same number.**]**
**SRS_CONNECTION_01_066: [**This means that if a bidirectional endpoint is constructed from an incoming channel endpoint and an outgoing channel endpoint, the channel number used for incoming frames is not necessarily the same as the channel number used for outgoing frames.**]**
...
Figure 2.18: Bidirectional Channel Multiplexing
Although not strictly directed at the connection endpoint, the begin and end frames are potentially useful for the connection endpoint to intercept as these frames are how sessions mark the beginning and ending of communication on a given channel (see section 2.5).
2.4.1 Opening A Connection
**SRS_CONNECTION_01_002: [**Each AMQP connection begins with an exchange of capabilities and limitations, including the maximum frame size.**]**
**SRS_CONNECTION_01_003: [**Prior to any explicit negotiation, the maximum frame size is 512 (MIN-MAX-FRAME-SIZE) and the maximum channel number is 0.**]**
**SRS_CONNECTION_01_004: [**After establishing or accepting a TCP connection and sending the protocol header, each peer MUST send an open frame before sending any other frames.**]**
**SRS_CONNECTION_01_005: [**The open frame describes the capabilities and limits of that peer.**]**
**SRS_CONNECTION_01_006: [**The open frame can only be sent on channel 0.**]**
**SRS_CONNECTION_01_007: [**After sending the open frame and reading its partner's open frame a peer MUST operate within mutually acceptable limitations from this point forward.**]**
...
Figure 2.19: Synchronous Connection Open Sequence
2.4.2 Pipelined Open
For applications that use many short-lived connections, it MAY be desirable to pipeline the connection negotiation process. A peer MAY do this by starting to send subsequent frames before receiving the partner's connection header or open frame. This is permitted so long as the pipelined frames are known a priori to conform to the capabilities and limitations of its partner. For example, this can be accomplished by keeping the use of the connection within the capabilities and limits expected of all AMQP implementations as defined by the specification of the open frame.
...
Figure 2.20: Pipelined Connection Open Sequence
The use of pipelined frames by a peer cannot be distinguished by the peer's partner from non-pipelined use so long as the pipelined frames conform to the partner's capabilities and limitations.
2.4.3 Closing A Connection
**SRS_CONNECTION_01_008: [**Prior to closing a connection, each peer MUST write a close frame with a code indicating the reason for closing.**]**
**SRS_CONNECTION_01_009: [**This frame MUST be the last thing ever written onto a connection.**]**
**SRS_CONNECTION_01_010: [**After writing this frame the peer SHOULD continue to read from the connection until it receives the partner's close frame **]**
**SRS_CONNECTION_01_011: [**(in order to guard against erroneously or maliciously implemented partners, a peer SHOULD implement a timeout to give its partner a reasonable time to receive and process the close before giving up and simply closing the underlying transport mechanism).**]**
**SRS_CONNECTION_01_012: [**A close frame MAY be received on any channel up to the maximum channel number negotiated in open.**]**
**SRS_CONNECTION_01_013: [**However, implementations SHOULD send it on channel 0**]** , and **SRS_CONNECTION_01_014: [**MUST send it on channel 0 if pipelined in a single batch with the corresponding open.**]**
...
Figure 2.21: Synchronous Connection Close Sequence
**SRS_CONNECTION_01_015: [**Implementations SHOULD NOT expect to be able to reuse open TCP sockets after close performatives have been exchanged.**]**
**SRS_CONNECTION_01_240: [**There is no requirement for an implementation to read from a socket after a close performative has been received.**]**
2.4.4 Simultaneous Close
Normally one peer will initiate the connection close, and the partner will send its close in response. However, because both endpoints MAY simultaneously choose to close the connection for independent reasons, it is possible for a simultaneous close to occur. In this case, the only potentially observable difference from the perspective of each endpoint is the code indicating the reason for the close.
...
Figure 2.22: Simultaneous Connection Close Sequence
2.4.5 Idle Timeout Of A Connection
**SRS_CONNECTION_01_017: [**Connections are subject to an idle timeout threshold.**]**
**SRS_CONNECTION_01_018: [**The timeout is triggered by a local peer when no frames are received after a threshold value is exceeded.**]**
**SRS_CONNECTION_01_019: [**The idle timeout is measured in milliseconds, and starts from the time the last frame is received.**]**
**SRS_CONNECTION_01_020: [**If the threshold is exceeded, then a peer SHOULD try to gracefully close the connection using a close frame with an error explaining why.**]**
**SRS_CONNECTION_01_021: [**If the remote peer does not respond gracefully within a threshold to this, then the peer MAY close the TCP socket.**]**
**SRS_CONNECTION_01_022: [**Each peer has its own (independent) idle timeout.**]**
**SRS_CONNECTION_01_023: [**At connection open each peer communicates the maximum period between activity (frames) on the connection that it desires from its partner.**]**
**SRS_CONNECTION_01_024: [**The open frame carries the idletime-out field for this purpose.**]**
**SRS_CONNECTION_01_025: [**To avoid spurious timeouts, the value in idle-time-out SHOULD be half the peer's actual timeout threshold.**]**
**SRS_CONNECTION_01_026: [**If a peer can not, for any reason support a proposed idle timeout, then it SHOULD close the connection using a close frame with an error explaining why.**]**
**SRS_CONNECTION_01_027: [**There is no requirement for peers to support arbitrarily short or long idle timeouts.**]**
**SRS_CONNECTION_01_028: [**The use of idle timeouts is in addition to any network protocol level control.**]**
**SRS_CONNECTION_01_029: [**Implementations SHOULD make use of TCP keep-alive wherever possible in order to be good citizens.**]**
**SRS_CONNECTION_01_030: [**If a peer needs to satisfy the need to send traffic to prevent idle timeout, and has nothing to send, it MAY send an empty frame, i.e., a frame consisting solely of a frame header, with no frame body.**]**
**SRS_CONNECTION_01_031: [**Implementations MUST be prepared to handle empty frames arriving on any valid channel**]** ,
**SRS_CONNECTION_01_032: [**though implementations SHOULD use channel 0 when sending empty frames**]** ,
**SRS_CONNECTION_01_033: [**and MUST use channel 0 if a maximum channel number has not yet been negotiated (i.e., before an open frame has been received).**]**
**SRS_CONNECTION_01_034: [**Apart from this use, empty frames have no meaning.**]**
**SRS_CONNECTION_01_035: [**Empty frames can only be sent after the open frame is sent.**]**
**SRS_CONNECTION_01_036: [**As they are a frame, they MUST NOT be sent after the close frame has been sent.**]**
**SRS_CONNECTION_01_037: [**As an alternative to using an empty frame to prevent an idle timeout, if a connection is in a permissible state, an implementation MAY choose to send a flow frame for a valid session.**]**
**SRS_CONNECTION_01_038: [**If during operation a peer exceeds the remote peer's idle timeout's threshold, e.g., because it is heavily loaded, it SHOULD gracefully close the connection by using a close frame with an error explaining why.**]**
2.4.6 Connection States
**SRS_CONNECTION_01_039: [**START In this state a connection exists, but nothing has been sent or received. This is the state an implementation would be in immediately after performing a socket connect or socket accept.**]**
**SRS_CONNECTION_01_040: [**HDR RCVD In this state the connection header has been received from the peer but a connection header has not been sent.**]**
**SRS_CONNECTION_01_041: [**HDR SENT In this state the connection header has been sent to the peer but no connection header has been received.**]**
**SRS_CONNECTION_01_042: [**HDR EXCH In this state the connection header has been sent to the peer and a connection header has been received from the peer.**]**
**SRS_CONNECTION_01_043: [**OPEN PIPE In this state both the connection header and the open frame have been sent but nothing has been received.**]**
**SRS_CONNECTION_01_044: [**OC PIPE In this state, the connection header, the open frame, any pipelined connection traffic, and the close frame have been sent but nothing has been received.**]**
**SRS_CONNECTION_01_045: [**OPEN RCVD In this state the connection headers have been exchanged. An open frame has been received from the peer but an open frame has not been sent.**]**
**SRS_CONNECTION_01_046: [**OPEN SENT In this state the connection headers have been exchanged. An open frame has been sent to the peer but no open frame has yet been received.**]**
**SRS_CONNECTION_01_047: [**CLOSE PIPE In this state the connection headers have been exchanged. An open frame, any pipelined connection traffic, and the close frame have been sent but no open frame has yet been received from the peer.**]**
**SRS_CONNECTION_01_048: [**OPENED In this state the connection header and the open frame have been both sent and received.**]**
**SRS_CONNECTION_01_049: [**CLOSE RCVD In this state a close frame has been received indicating that the peer has initiated an AMQP close.**]**
**SRS_CONNECTION_01_050: [**No further frames are expected to arrive on the connection;**]**
**SRS_CONNECTION_01_051: [**however, frames can still be sent.**]**
**SRS_CONNECTION_01_052: [**If desired, an implementation MAY do a TCP half-close at this point to shut down the read side of the connection.**]**
**SRS_CONNECTION_01_053: [**CLOSE SENT In this state a close frame has been sent to the peer. It is illegal to write anything more onto the connection, however there could potentially still be incoming frames.**]**
**SRS_CONNECTION_01_054: [**If desired, an implementation MAY do a TCP half-close at this point to shutdown the write side of the connection.**]**
**SRS_CONNECTION_01_055: [**DISCARDING The DISCARDING state is a variant of the CLOSE SENT state where the close is triggered by an error.**]**
**SRS_CONNECTION_01_056: [**In this case any incoming frames on the connection MUST be silently discarded until the peer's close frame is received.**]**
**SRS_CONNECTION_01_057: [**END In this state it is illegal for either endpoint to write anything more onto the connection. The connection can be safely closed and discarded.**]**
2.4.7 Connection State Diagram
The graph below depicts a complete state diagram for each endpoint. The boxes represent states, and the arrows represent state transitions. Each arrow is labeled with the action that triggers that particular transition.
...
Figure 2.23: Connection State Diagram
State Legal Sends Legal Receives Legal Connection Actions
**SRS_CONNECTION_01_224: [**START HDR HDR**]**
**SRS_CONNECTION_01_225: [**HDR_RCVD HDR OPEN**]**
**SRS_CONNECTION_01_226: [**HDR_SENT OPEN HDR**]**
**SRS_CONNECTION_01_227: [**HDR_EXCH OPEN OPEN**]**
**SRS_CONNECTION_01_228: [**OPEN_RCVD OPEN \* **]**
**SRS_CONNECTION_01_229: [**OPEN_SENT \*\* OPEN**]**
**SRS_CONNECTION_01_230: [**OPEN_PIPE \*\* HDR**]**
**SRS_CONNECTION_01_231: [**CLOSE_PIPE - OPEN TCP Close for Write**]**
**SRS_CONNECTION_01_232: [**OC_PIPE - HDR TCP Close for Write**]**
**SRS_CONNECTION_01_233: [**OPENED \* ***]**
**SRS_CONNECTION_01_234: [**CLOSE_RCVD \* - TCP Close for Read**]**
**SRS_CONNECTION_01_235: [**CLOSE_SENT - \* TCP Close for Write**]**
**SRS_CONNECTION_01_236: [**DISCARDING - \* TCP Close for Write**]**
**SRS_CONNECTION_01_237: [**END - - TCP Close**]**
\* = any frames
- = no frames
\*\* = any frame known a priori to conform to the
peer's capabilities and limitations
Figure 2.24: Connection State Table
##Open performative ISO section
2.7.1 Open
Negotiate connection parameters.
\<type name="open" class="composite" source="list" provides="frame">
\<descriptor name="amqp:open:list" code="0x00000000:0x00000010"/>
**SRS_CONNECTION_01_171: [**\<field name="container-id" type="string" mandatory="true"/>**]**
**SRS_CONNECTION_01_172: [**\<field name="hostname" type="string"/>**]**
**SRS_CONNECTION_01_173: [**\<field name="max-frame-size" type="uint" default="4294967295"/>**]**
**SRS_CONNECTION_01_174: [**\<field name="channel-max" type="ushort" default="65535"/>**]**
**SRS_CONNECTION_01_175: [**\<field name="idle-time-out" type="milliseconds"/>**]**
**SRS_CONNECTION_01_176: [**\<field name="outgoing-locales" type="ietf-language-tag" multiple="true"/>**]**
**SRS_CONNECTION_01_177: [**\<field name="incoming-locales" type="ietf-language-tag" multiple="true"/>**]**
**SRS_CONNECTION_01_178: [**\<field name="offered-capabilities" type="symbol" multiple="true"/>**]**
**SRS_CONNECTION_01_179: [**\<field name="desired-capabilities" type="symbol" multiple="true"/>**]**
**SRS_CONNECTION_01_180: [**\<field name="properties" type="fields"/>**]**
\</type>
The first frame sent on a connection in either direction MUST contain an open performative. Note that the connection header which is sent first on the connection is not a frame. The fields indicate the capabilities and limitations of the sending peer.
Field Details
container-id the id of the source container
hostname the name of the target host
The name of the host (either fully qualified or relative) to which the sending peer is connecting. It is
not mandatory to provide the hostname. If no hostname is provided the receiving peer SHOULD
select a default based on its own configuration. This field can be used by AMQP proxies to
determine the correct back-end service to connect the client to. This field MAY already have been specified by the sasl-init frame, if a SASL layer is used, or, the server name indication extension as described in RFC-4366, if a TLS layer is used, in which case this field SHOULD be null or contain the same value. It is undefined what a different value to that already specified means.
max-frame-size proposed maximum frame size
The largest frame size that the sending peer is able to accept on this connection. If this field is not set it means that the peer does not impose any specific limit. A peer MUST NOT send
frames larger than its partner can handle. A peer that receives an oversized frame MUST close
the connection with the framing-error error-code. **SRS_CONNECTION_01_167: [**Both peers MUST accept frames of up to 512 (MIN-MAX-FRAME-SIZE) octets.**]**
channel-max the maximum channel number that can be used on the connection
The channel-max value is the highest channel number that can be used on the connection. This
value plus one is the maximum number of sessions that can be simultaneously active on the connection. A peer MUST not use channel numbers outside the range that its partner can handle. A peer that receives a channel number outside the supported range MUST close the connection with the framing-error error-code.
idle-time-out idle time-out
The idle timeout REQUIRED by the sender (see subsection 2.4.5). **SRS_CONNECTION_01_192: [**A value of zero is the same as if it was not set (null).**]** If the receiver is unable or unwilling to support the idle time-out then it SHOULD close the connection with an error explaining why (e.g., because it is too small).
If the value is not set, then the sender does not have an idle time-out. However, senders doing
this SHOULD be aware that implementations MAY choose to use an internal default to efficiently
manage a peer's resources.
outgoing-locales locales available for outgoing text
A list of the locales that the peer supports for sending informational text. This includes connection,
session and link error descriptions. A peer MUST support at least the en-US locale (see subsection
2.8.12 IETF Language Tag). Since this value is always supported, it need not be supplied in
the outgoing-locales. A null value or an empty list implies that only en-US is supported.
incoming-locales desired locales for incoming text in decreasing level of preference
A list of locales that the sending peer permits for incoming informational text. This list is ordered
in decreasing level of preference. The receiving partner will choose the first (most preferred)
incoming locale from those which it supports. If none of the requested locales are supported, en-
US will be chosen. Note that en-US need not be supplied in this list as it is always the fallback. A
peer MAY determine which of the permitted incoming locales is chosen by examining the partner's
supported locales as specified in the outgoing-locales field. A null value or an empty list implies
that only en-US is supported.
offered-capabilities extension capabilities the sender supports
If the receiver of the offered-capabilities requires an extension capability which is not present in
the offered-capability list then it MUST close the connection.
A registry of commonly defined connection capabilities and their meanings is maintained [AMQPCONNCAP].
desired-capabilities extension capabilities the sender can use if the receiver supports them
The desired-capability list defines which extension capabilities the sender MAY use if the receiver
offers them (i.e., they are in the offered-capabilities list received by the sender of the desired capabilities).
The sender MUST NOT attempt to use any capabilities it did not declare in the desired-capabilities field. If the receiver of the desired-capabilities offers extension capabilities which are not present in the desired-capabilities list it received, then it can be sure those (undesired) capabilities will not be used on the connection.
properties connection properties
The properties map contains a set of fields intended to indicate information about the connection
and its container.
A registry of commonly defined connection properties and their meanings is maintained [AMQPCONNPROP].
##Close frame performative section
2.7.9 Close
Signal a connection close.
\<type name="close" class="composite" source="list" provides="frame">
\<descriptor name="amqp:close:list" code="0x00000000:0x00000018"/>
\<field name="error" type="error"/>
\</type>
Sending a close signals that the sender will not be sending any more frames (or bytes of any other kind) on the connection. Orderly shutdown requires that this frame MUST be written by the sender. It is illegal to send any more frames (or bytes of any other kind) after sending a close frame.
Field Details
error error causing the close
**SRS_CONNECTION_01_238: [**If set, this field indicates that the connection is being closed due to an error condition.**]** The value of the field SHOULD contain details on the cause of the error.

Просмотреть файл

@ -0,0 +1,200 @@
#frame_codec requirements
##Overview
frame_codec is module that encodes/decodes frames (regardless of their type).
##Exposed API
```C
typedef struct FRAME_CODEC_INSTANCE_TAG* FRAME_CODEC_HANDLE;
typedef void(*ON_FRAME_RECEIVED)(void* context, const unsigned char* type_specific, uint32_t type_specific_size, const unsigned char* frame_body, uint32_t frame_body_size);
typedef void(*ON_FRAME_CODEC_ERROR)(void* context);
typedef void(*ON_BYTES_ENCODED)(void* context, const unsigned char* bytes, size_t length, bool encode_complete);
extern FRAME_CODEC_HANDLE frame_codec_create(ON_FRAME_CODEC_ERROR on_frame_codec_error, void* callback_context, LOGGER_LOG logger_log);
extern void frame_codec_destroy(FRAME_CODEC_HANDLE frame_codec);
extern int frame_codec_set_max_frame_size(FRAME_CODEC_HANDLE frame_codec, uint32_t max_frame_size);
extern int frame_codec_subscribe(FRAME_CODEC_HANDLE frame_codec, uint8_t type, ON_FRAME_RECEIVED on_frame_received, void* callback_context);
extern int frame_codec_unsubscribe(FRAME_CODEC_HANDLE frame_codec, uint8_t type);
extern int frame_codec_receive_bytes(FRAME_CODEC_HANDLE frame_codec, const unsigned char* buffer, size_t size);
extern int frame_codec_encode_frame(FRAME_CODEC_HANDLE frame_codec, uint8_t type, const PAYLOAD* payloads, size_t payload_count, const unsigned char* type_specific_bytes, uint32_t type_specific_size, ON_BYTES_ENCODED encoded_bytes, void* callback_context);
```
###frame_codec_create
```C
extern FRAME_CODEC_HANDLE frame_codec_create(ON_FRAME_CODEC_ERROR on_frame_codec_error, void* callback_context, LOGGER_LOG logger_log);
```
**SRS_FRAME_CODEC_01_021: [**frame_codec_create shall create a new instance of frame_codec and return a non-NULL handle to it on success.**]**
**SRS_FRAME_CODEC_01_020: [**If the on_frame_codec_error argument is NULL, frame_codec_create shall return NULL.**]**
**SRS_FRAME_CODEC_01_022: [**If allocating memory for the frame_codec instance fails, frame_codec_create shall return NULL.**]**
**SRS_FRAME_CODEC_01_082: [**The initial max_frame_size_shall be 512.**]**
**SRS_FRAME_CODEC_01_104: [**The callback_context shall be allowed to be NULL.**]**
###frame_codec_destroy
```C
extern void frame_codec_destroy(FRAME_CODEC frame_codec);
```
**SRS_FRAME_CODEC_01_023: [**frame_codec_destroy shall free all resources associated with a frame_codec instance.**]**
**SRS_FRAME_CODEC_01_024: [**If frame_codec is NULL, frame_codec_destroy shall do nothing.**]**
###frame_codec_set_max_frame_size
```C
extern int frame_codec_set_max_frame_size(FRAME_CODEC_HANDLE frame_codec, uint32_t max_frame_size);
```
**SRS_FRAME_CODEC_01_075: [**frame_codec_set_max_frame_size shall set the maximum frame size for a frame_codec.**]**
**SRS_FRAME_CODEC_01_076: [**On success, frame_codec_set_max_frame_size shall return 0.**]**
**SRS_FRAME_CODEC_01_077: [**If frame_codec is NULL, frame_codec_set_max_frame_size shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_078: [**If max_frame_size is invalid according to the AMQP standard, frame_codec_set_max_frame_size shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_079: [**The new frame size shall take effect immediately, even for a frame that is being decoded at the time of the call.**]**
**SRS_FRAME_CODEC_01_081: [**If a frame being decoded already has a size bigger than the max_frame_size argument then frame_codec_set_max_frame_size shall return a non-zero value and the previous frame size shall be kept.**]**
**SRS_FRAME_CODEC_01_097: [**Setting a frame size on a frame_codec that had a decode error shall fail.**]**
**SRS_FRAME_CODEC_01_098: [**Setting a frame size on a frame_codec that had an encode error shall fail.**]**
###frame_codec_receive_bytes
```C
extern int frame_codec_receive_bytes(FRAME_CODEC frame_codec, const unsigned char* buffer, size_t size);
```
**SRS_FRAME_CODEC_01_025: [**frame_codec_receive_bytes decodes a sequence of bytes into frames and on success it shall return zero.**]**
**SRS_FRAME_CODEC_01_026: [**If frame_codec or buffer are NULL, frame_codec_receive_bytes shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_027: [**If size is zero, frame_codec_receive_bytes shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_028: [**The sequence of bytes shall be decoded according to the AMQP ISO.**]**
**SRS_FRAME_CODEC_01_029: [**The sequence of bytes does not have to be a complete frame, frame_codec shall be responsible for maintaining decoding state between frame_codec_receive_bytes calls.**]**
**SRS_FRAME_CODEC_01_030: [**If a decoding error occurs, frame_codec_receive_bytes shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_074: [**If a decoding error is detected, any subsequent calls on frame_codec_receive_bytes shall fail.**]**
**SRS_FRAME_CODEC_01_031: [**When a complete frame is successfully decoded it shall be indicated to the upper layer by invoking the on_frame_received passed to frame_codec_subscribe.**]**
**SRS_FRAME_CODEC_01_032: [**Besides passing the frame information, the callback_context value passed to frame_codec_subscribe shall be passed to the on_frame_received function.**]**
**SRS_FRAME_CODEC_01_099: [**A pointer to the frame_body bytes shall also be passed to the on_frame_received.**]**
**SRS_FRAME_CODEC_01_102: [**frame_codec_receive_bytes shall allocate memory to hold the frame_body bytes.**]**
**SRS_FRAME_CODEC_01_101: [**If the memory for the frame_body bytes cannot be allocated, frame_codec_receive_bytes shall fail and return a non-zero value.**]**
**SRS_FRAME_CODEC_01_100: [**If the frame body size is 0, the frame_body pointer passed to on_frame_received shall be NULL.**]**
**SRS_FRAME_CODEC_01_096: [**If a frame bigger than the current max frame size is received, frame_codec_receive_bytes shall fail and return a non-zero value.**]**
**SRS_FRAME_CODEC_01_103: [**Upon any decode error, if an error callback has been passed to frame_codec_create, then the error callback shall be called with the context argument being the frame_codec_error_callback_context argument passed to frame_codec_create.**]**
###frame_codec_subscribe
```C
extern int frame_codec_subscribe(FRAME_CODEC_HANDLE frame_codec, uint8_t type, ON_FRAME_RECEIVED on_frame_received, void* callback_context);
```
**SRS_FRAME_CODEC_01_033: [**frame_codec_subscribe subscribes for a certain type of frame received by the frame_codec instance identified by frame_codec.**]**
**SRS_FRAME_CODEC_01_087: [**On success, frame_codec_subscribe shall return zero.**]**
**SRS_FRAME_CODEC_01_034: [**If any of the frame_codec or on_frame_received arguments is NULL, frame_codec_subscribe shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_035: [**After successfully registering a callback for a certain frame type, when subsequently that frame type is received the callbacks shall be invoked, passing to it the received frame and the callback_context value.**]**
**SRS_FRAME_CODEC_01_036: [**Only one callback pair shall be allowed to be registered for a given frame type.**]**
**SRS_FRAME_CODEC_01_037: [**If any failure occurs while performing the subscribe operation, frame_codec_subscribe shall return a non-zero value.**]**
###frame_codec_unsubscribe
```C
extern int frame_codec_unsubscribe(FRAME_CODEC frame_codec, uint8_t type);
```
**SRS_FRAME_CODEC_01_038: [**frame_codec_unsubscribe removes a previous subscription for frames of type type and on success it shall return 0.**]**
**SRS_FRAME_CODEC_01_039: [**If frame_codec is NULL, frame_codec_unsubscribe shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_040: [**If no subscription for the type frame type exists, frame_codec_unsubscribe shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_041: [**If any failure occurs while performing the unsubscribe operation, frame_codec_unsubscribe shall return a non-zero value.**]**
###frame_codec_encode_frame
```C
extern int frame_codec_encode_frame(FRAME_CODEC_HANDLE frame_codec, uint8_t type, const PAYLOAD* payloads, size_t payload_count, const unsigned char* type_specific_bytes, uint32_t type_specific_size, ON_BYTES_ENCODED encoded_bytes, void* callback_context);
```
**SRS_FRAME_CODEC_01_042: [**frame_codec_encode_frame encodes the header and type specific bytes of a frame that has frame_payload_size bytes.**]**
**SRS_FRAME_CODEC_01_043: [**On success it shall return 0.**]**
**SRS_FRAME_CODEC_01_044: [**If the argument frame_codec is NULL, frame_codec_encode_frame shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_107: [**If the argument payloads is NULL and payload_count is non-zero, frame_codec_encode_frame shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_090: [**If the type_specific_size – 2 does not divide by 4, frame_codec_encode_frame shall pad the type_specific bytes with zeroes so that type specific data is according to the AMQP ISO.**]**
**SRS_FRAME_CODEC_01_092: [**If type_specific_size is too big to allow encoding the frame according to the AMQP ISO then frame_codec_encode_frame shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_091: [**If the argument type_specific_size is greater than 0 and type_specific_bytes is NULL, frame_codec_encode_frame shall return a non-zero value.**]**
**SRS_FRAME_CODEC_01_105: [**The frame_payload_size shall be computed by summing up the lengths of the payload segments identified by the payloads argument.**]**
**SRS_FRAME_CODEC_01_106: [**All payloads shall be encoded in order as part of the frame.**]**
**SRS_FRAME_CODEC_01_088: [**Encoded bytes shall be passed to the on_bytes_encoded callback.**]**
**SRS_FRAME_CODEC_01_095: [**If the frame_size needed for the frame is bigger than the maximum frame size, frame_codec_encode_frame shall fail and return a non-zero value.**]**
##ISO section (receive)
2.3 Framing
**SRS_FRAME_CODEC_01_001: [**Frames are divided into three distinct areas: a fixed width frame header, a variable width extended header, and a variable width frame body.**]**
...
Figure 2.14: Frame Layout
**SRS_FRAME_CODEC_01_002: [**frame header The frame header is a fixed size (8 byte) structure that precedes each frame.**]**
**SRS_FRAME_CODEC_01_003: [**The frame header includes mandatory information necessary to parse the rest of the frame including size and type information.**]**
**SRS_FRAME_CODEC_01_004: [**extended header The extended header is a variable width area preceding the frame body.**]**
**SRS_FRAME_CODEC_01_005: [**This is an extension point defined for future expansion.**]**
**SRS_FRAME_CODEC_01_006: [**The treatment of this area depends on the frame type.**]**
**SRS_FRAME_CODEC_01_007: [**frame body The frame body is a variable width sequence of bytes the format of which depends on the frame type.**]**
2.3.1 Frame Layout
The diagram below shows the details of the general frame layout for all frame types.
...
Figure 2.15: General Frame Layout
**SRS_FRAME_CODEC_01_008: [**SIZE Bytes 0-3 of the frame header contain the frame size.**]**
**SRS_FRAME_CODEC_01_009: [**This is an unsigned 32-bit integer that MUST contain the total frame size of the frame header, extended header, and frame body.**]**
**SRS_FRAME_CODEC_01_010: [**The frame is malformed if the size is less than the size of the frame header (8 bytes).**]**
**SRS_FRAME_CODEC_01_011: [**DOFF Byte 4 of the frame header is the data offset.**]**
**SRS_FRAME_CODEC_01_012: [**This gives the position of the body within the frame.**]**
**SRS_FRAME_CODEC_01_013: [**The value of the data offset is an unsigned, 8-bit integer specifying a count of 4-byte words.**]**
**SRS_FRAME_CODEC_01_014: [**Due to the mandatory 8-byte frame header, the frame is malformed if the value is less than 2.**]**
**SRS_FRAME_CODEC_01_015: [**TYPE Byte 5 of the frame header is a type code.**]**
**SRS_FRAME_CODEC_01_016: [**The type code indicates the format and purpose of the frame.**]**
**SRS_FRAME_CODEC_01_017: [**The subsequent bytes in the frame header MAY be interpreted differently depending on the type of the frame.**]**
**SRS_FRAME_CODEC_01_018: [**A type code of 0x00 indicates that the frame is an AMQP frame.**]**
**SRS_FRAME_CODEC_01_019: [**A type code of 0x01 indicates that the frame is a SASL frame**]** , see Part 5: section 5.3.
##ISO section (send)
2.3 Framing
**SRS_FRAME_CODEC_01_055: [**Frames are divided into three distinct areas: a fixed width frame header, a variable width extended header, and a variable width frame body.**]**
...
Figure 2.14: Frame Layout
**SRS_FRAME_CODEC_01_056: [**frame header The frame header is a fixed size (8 byte) structure that precedes each frame.**]**
**SRS_FRAME_CODEC_01_057: [**The frame header includes mandatory information necessary to parse the rest of the frame including size and type information.**]**
**SRS_FRAME_CODEC_01_058: [**extended header The extended header is a variable width area preceding the frame body.**]**
**SRS_FRAME_CODEC_01_059: [**This is an extension point defined for future expansion.**]**
**SRS_FRAME_CODEC_01_060: [**The treatment of this area depends on the frame type.**]**
**SRS_FRAME_CODEC_01_061: [**frame body The frame body is a variable width sequence of bytes the format of which depends on the frame type.**]**
2.3.1 Frame Layout
The diagram below shows the details of the general frame layout for all frame types.
...
Figure 2.15: General Frame Layout
**SRS_FRAME_CODEC_01_062: [**SIZE Bytes 0-3 of the frame header contain the frame size.**]**
**SRS_FRAME_CODEC_01_063: [**This is an unsigned 32-bit integer that MUST contain the total frame size of the frame header, extended header, and frame body.**]**
**SRS_FRAME_CODEC_01_064: [**The frame is malformed if the size is less than the size of the frame header (8 bytes).**]**
**SRS_FRAME_CODEC_01_065: [**DOFF Byte 4 of the frame header is the data offset.**]**
**SRS_FRAME_CODEC_01_066: [**This gives the position of the body within the frame.**]**
**SRS_FRAME_CODEC_01_067: [**The value of the data offset is an unsigned, 8-bit integer specifying a count of 4-byte words.**]**
**SRS_FRAME_CODEC_01_068: [**Due to the mandatory 8-byte frame header, the frame is malformed if the value is less than 2.**]**
**SRS_FRAME_CODEC_01_069: [**TYPE Byte 5 of the frame header is a type code.**]**
**SRS_FRAME_CODEC_01_070: [**The type code indicates the format and purpose of the frame.**]**
**SRS_FRAME_CODEC_01_071: [**The subsequent bytes in the frame header MAY be interpreted differently depending on the type of the frame.**]**
**SRS_FRAME_CODEC_01_072: [**A type code of 0x00 indicates that the frame is an AMQP frame.**]**
**SRS_FRAME_CODEC_01_073: [**A type code of 0x01 indicates that the frame is a SASL frame**]** , see Part 5: section 5.3.

1
devdoc/iso_deviations.md Normal file
Просмотреть файл

@ -0,0 +1 @@
SRS_CONNECTION_01_239: The ISO does not define what should happen if an OPEN frame is received in the OPENED state.

Просмотреть файл

@ -0,0 +1,10 @@
#link requirements
##Overview
link is module that implements the link layer in the AMQP ISO.
##Exposed API
###link_create

Просмотреть файл

@ -0,0 +1,166 @@
#message requirements
##Overview
message is module that stores AMQP messages per the Messaging layer in the AMQP ISO.
##Exposed API
```C
extern MESSAGE_HANDLE message_create(void);
extern MESSAGE_HANDLE message_clone(MESSAGE_HANDLE source_message);
extern void message_destroy(MESSAGE_HANDLE message);
extern int message_set_header(MESSAGE_HANDLE handle, HEADER_HANDLE message_header);
extern int message_get_header(MESSAGE_HANDLE handle, HEADER_HANDLE* message_header);
extern int message_set_delivery_annotations(MESSAGE_HANDLE handle, annotations delivery_annotations);
extern int message_get_delivery_annotations(MESSAGE_HANDLE handle, annotations* delivery_annotations);
extern int message_set_message_annotations(MESSAGE_HANDLE handle, annotations delivery_annotations);
extern int message_get_message_annotations(MESSAGE_HANDLE handle, annotations* delivery_annotations);
extern int message_set_properties(MESSAGE_HANDLE handle, PROPERTIES_HANDLE properties);
extern int message_get_properties(MESSAGE_HANDLE handle, PROPERTIES_HANDLE* properties);
extern int message_set_application_properties(MESSAGE_HANDLE handle, AMQP_VALUE application_properties);
extern int message_get_application_properties(MESSAGE_HANDLE handle, AMQP_VALUE* application_properties);
extern int message_set_footer(MESSAGE_HANDLE handle, annotations footer);
extern int message_get_footer(MESSAGE_HANDLE handle, annotations* footer);
extern int message_set_body_amqp_data(MESSAGE_HANDLE handle, BINARY_DATA binary_data);
extern int message_get_body_amqp_data(MESSAGE_HANDLE handle, BINARY_DATA* binary_data);
```
###message_create
```C
extern MESSAGE_HANDLE message_create(void);
```
**SRS_MESSAGE_01_001: [**message_create shall create a new AMQP message instance and on success it shall return a non-NULL handle for the newly created message instance.**]**
**SRS_MESSAGE_01_002: [**If allocating memory for the message fails, message_create shall fail and return NULL.**]**
###message_clone
```C
extern MESSAGE_HANDLE message_clone(MESSAGE_HANDLE source_message);
```
**SRS_MESSAGE_01_003: [**message_clone shall clone a message entirely and on success return a non-NULL handle to the cloned message.**]**
**SRS_MESSAGE_01_062: [**If source_message is NULL, message_clone shall fail and return NULL.**]**
**SRS_MESSAGE_01_004: [**If allocating memory for the new cloned message fails, message_clone shall fail and return NULL.**]**
**SRS_MESSAGE_01_005: [**If a header exists on the source message it shall be cloned by using header_clone.**]**
**SRS_MESSAGE_01_006: [**If delivery annotations exist on the source message they shall be cloned by using annotations_clone.**]**
**SRS_MESSAGE_01_007: [**If message annotations exist on the source message they shall be cloned by using annotations_clone.**]**
**SRS_MESSAGE_01_008: [**If message properties exist on the source message they shall be cloned by using properties_clone.**]**
**SRS_MESSAGE_01_009: [**If application properties exist on the source message they shall be cloned by using amqpvalue_clone.**]**
**SRS_MESSAGE_01_010: [**If a footer exists on the source message it shall be cloned by using annotations_clone.**]**
**SRS_MESSAGE_01_011: [**If an AMQP data has been set as message body on the source message it shall be cloned by allocating memory for the binary payload.**]**
**SRS_MESSAGE_01_012: [**If any cloning operation for the members of the source message fails, then message_clone shall fail and return NULL.**]**
###message_destroy
```C
extern void message_destroy(MESSAGE_HANDLE message);
```
**SRS_MESSAGE_01_013: [**message_destroy shall free all resources allocated by the message instance identified by the message argument.**]**
**SRS_MESSAGE_01_014: [**If message is NULL, message_destroy shall do nothing.**]**
**SRS_MESSAGE_01_015: [**The message header shall be freed by calling header_destroy.**]**
**SRS_MESSAGE_01_016: [**The delivery annotations shall be freed by calling annotations_destroy.**]**
**SRS_MESSAGE_01_017: [**The message annotations shall be freed by calling annotations_destroy.**]**
**SRS_MESSAGE_01_018: [**The message properties shall be freed by calling properties_destroy.**]**
**SRS_MESSAGE_01_019: [**The application properties shall be freed by calling amqpvalue_destroy.**]**
**SRS_MESSAGE_01_020: [**The message footer shall be freed by calling annotations_destroy.**]**
**SRS_MESSAGE_01_021: [**If the message body is made of an AMQP data, the memory buffer holding it shall be freed by calling amqpalloc_free.**]**
###message_set_header
```C
extern int message_set_header(MESSAGE_HANDLE message, HEADER_HANDLE message_header);
```
**SRS_MESSAGE_01_022: [**message_set_header shall copy the contents of message_header as the header for the message instance identified by message.**]**
**SRS_MESSAGE_01_023: [**On success it shall return 0.**]**
**SRS_MESSAGE_01_024: [**If message or message_header is NULL, message_set_header shall fail and return a non-zero value.**]**
**SRS_MESSAGE_01_025: [**Cloning the header shall be done by calling header_clone.**]**
**SRS_MESSAGE_01_026: [**If header_clone fails, message_set_header shall fail and return a non-zero value.**]**
###message_get_header
```C
extern int message_get_header(MESSAGE_HANDLE message, HEADER_HANDLE* message_header);
```
**SRS_MESSAGE_01_027: [**message_get_header shall copy the contents of header for the message instance identified by message into the argument message_header.**]**
**SRS_MESSAGE_01_028: [**On success, message_get_header shall return 0.**]** **SRS_MESSAGE_01_029: [**If message or message_header is NULL, message_get_header shall fail and return a non-zero value.**]**
**SRS_MESSAGE_01_030: [**Cloning the header shall be done by calling header_clone.**]**
**SRS_MESSAGE_01_031: [**If header_clone fails, message_get_header shall fail and return a non-zero value.**]**
###message_set_delivery_annotations
```C
extern int message_set_delivery_annotations(MESSAGE_HANDLE message, annotations delivery_annotations);
```
**SRS_MESSAGE_01_032: [**message_set_delivery_annotations shall copy the contents of delivery_annotations as the delivery annotations for the message instance identified by message.**]**
**SRS_MESSAGE_01_033: [**On success it shall return 0.**]**
**SRS_MESSAGE_01_034: [**If message or delivery_annotations is NULL, message_set_delivery_annotations shall fail and return a non-zero value.**]**
**SRS_MESSAGE_01_035: [**Cloning the delivery annotations shall be done by calling annotations_clone.**]**
**SRS_MESSAGE_01_036: [**If annotations_clone fails, message_set_delivery_annotations shall fail and return a non-zero value.**]**
###message_get_delivery_annotations
```C
extern int message_get_delivery_annotations(MESSAGE_HANDLE message, annotations* delivery_annotations);
```
**SRS_MESSAGE_01_037: [**message_get_delivery_annotations shall copy the contents of delivery annotations for the message instance identified by message into the argument delivery_annotations.**]**
**SRS_MESSAGE_01_038: [**On success, message_get_delivery_annotations shall return 0.**]**
**SRS_MESSAGE_01_039: [**If message or delivery_annotations is NULL, message_get_delivery_annotations shall fail and return a non-zero value.**]**
**SRS_MESSAGE_01_040: [**Cloning the delivery annotations shall be done by calling annotations_clone.**]**
**SRS_MESSAGE_01_041: [**If annotations_clone fails, message_get_delivery_annotations shall fail and return a non-zero value.**]**
###message_set_message_annotations
```C
extern int message_set_message_annotations(MESSAGE_HANDLE message, annotations delivery_annotations);
```
**SRS_MESSAGE_01_042: [**message_set_message_annotations shall copy the contents of message_annotations as the message annotations for the message instance identified by message.**]**
**SRS_MESSAGE_01_043: [**On success it shall return 0.**]**
**SRS_MESSAGE_01_044: [**If message or message_annotations is NULL, message_set_message_annotations shall fail and return a non-zero value.**]**
**SRS_MESSAGE_01_045: [**Cloning the message annotations shall be done by calling annotations_clone.**]**
**SRS_MESSAGE_01_046: [**If annotations_clone fails, message_set_message_annotations shall fail and return a non-zero value.**]**
###message_get_message_annotations
```C
extern int message_get_message_annotations(MESSAGE_HANDLE message, annotations* delivery_annotations);
```
**SRS_MESSAGE_01_047: [**message_get_message_annotations shall copy the contents of message annotations for the message instance identified by message into the argument message_annotations.**]**
**SRS_MESSAGE_01_048: [**On success, message_get_message_annotations shall return 0.**]**
**SRS_MESSAGE_01_049: [**If message or message_annotations is NULL, message_get_message_annotations shall fail and return a non-zero value.**]**
**SRS_MESSAGE_01_050: [**Cloning the message annotations shall be done by calling annotations_clone.**]**
**SRS_MESSAGE_01_051: [**If annotations_clone fails, message_get_message_annotations shall fail and return a non-zero value.**]**
###message_set_properties
```C
extern int message_set_properties(MESSAGE_HANDLE message, PROPERTIES_HANDLE properties);
```
**SRS_MESSAGE_01_052: [**message_set_properties shall copy the contents of properties as the message properties for the message instance identified by message.**]**
**SRS_MESSAGE_01_053: [**On success it shall return 0.**]**
**SRS_MESSAGE_01_054: [**If message or properties is NULL, message_set_properties shall fail and return a non-zero value.**]**
**SRS_MESSAGE_01_055: [**Cloning the message properties shall be done by calling properties_clone.**]**
**SRS_MESSAGE_01_056: [**If properties_clone fails, message_set_properties shall fail and return a non-zero value.**]**
###message_get_properties
```C
extern int message_get_properties(MESSAGE_HANDLE message, PROPERTIES_HANDLE* properties);
```
**SRS_MESSAGE_01_057: [**message_get_properties shall copy the contents of message properties for the message instance identified by message into the argument properties.**]**
**SRS_MESSAGE_01_058: [**On success, message_get_properties shall return 0.**]**
**SRS_MESSAGE_01_059: [**If message or properties is NULL, message_get_properties shall fail and return a non-zero value.**]**
**SRS_MESSAGE_01_060: [**Cloning the message properties shall be done by calling properties_clone.**]**
**SRS_MESSAGE_01_061: [**If properties_clone fails, message_get_properties shall fail and return a non-zero value.**]**

Просмотреть файл

@ -0,0 +1,62 @@
#sasl_anonymous requirements
##Overview
sasl_anonymous is a module that implements the sasl mechanism ANONYMOUS so that it can be used through the sasl_mechanism interface.
##Exposed API
```C
extern CONCRETE_SASL_MECHANISM_HANDLE saslanonymous_create(void* config);
extern void saslanonymous_destroy(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
extern int saslanonymous_get_init_bytes(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism, INIT_BYTES* init_bytes);
extern const char* saslanonymous_get_mechanism_name(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
extern const SASL_MECHANISM_INTERFACE_DESCRIPTION* saslanonymous_get_interface(void);
```
###saslanonymous_create
```C
extern CONCRETE_SASL_MECHANISM_HANDLE saslanonymous_create(void* config);
```
**SRS_SASL_ANONYMOUS_01_001: [**saslanonymous_create shall return on success a non-NULL handle to a new SASL anonymous mechanism.**]**
**SRS_SASL_ANONYMOUS_01_002: [**If allocating the memory needed for the saslanonymous instance fails then saslanonymous_create shall return NULL.**]**
**SRS_SASL_ANONYMOUS_01_003: [**Since this is the ANONYMOUS SASL mechanism, config shall be ignored.**]**
###saslanonymous_destroy
```C
extern void saslanonymous_destroy(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
```
**SRS_SASL_ANONYMOUS_01_004: [**saslannymous_destroy shall free all resources associated with the SASL mechanism.**]**
**SRS_SASL_ANONYMOUS_01_005: [**If the argument concrete_sasl_mechanism is NULL, saslannymous_destroy shall do nothing.**]**
###saslanonymous_get_init_bytes
```C
extern int saslanonymous_get_init_bytes(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism, INIT_BYTES* init_bytes);
```
**SRS_SASL_ANONYMOUS_01_006: [**saslanonymous_get_init_bytes shall validate the concrete_sasl_mechanism argument and set the length of the init_bytes argument to be zero.**]**
**SRS_SASL_ANONYMOUS_01_012: [**The bytes field of init_buffer shall be set to NULL.**]**
**SRS_SASL_ANONYMOUS_01_011: [**On success saslanonymous_get_init_bytes shall return zero.**]**
**SRS_SASL_ANONYMOUS_01_007: [**If the any argument is NULL, saslanonymous_get_init_bytes shall return a non-zero value.**]**
###saslanonymous_get_mechanism_name
```C
extern const char* saslanonymous_get_mechanism_name(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
```
**SRS_SASL_ANONYMOUS_01_008: [**saslanonymous_get_mechanism_name shall validate the argument concrete_sasl_mechanism and on success it shall return a pointer to the string “ANONYMOUS”.**]**
**SRS_SASL_ANONYMOUS_01_009: [**If the argument concrete_sasl_mechanism is NULL, saslanonymous_get_mechanism_name shall return NULL.**]**
###saslanonymous_get_interface
```C
extern const SASL_MECHANISM_INTERFACE_DESCRIPTION* saslanonymous_get_interface(void);
```
**SRS_SASL_ANONYMOUS_01_010: [**saslanonymous_get_interface shall return a pointer to a SASL_MECHANISM_INTERFACE_DESCRIPTION structure that contains pointers to the functions: saslanonymous_create, saslanonymous_destroy, saslanonymous_get_init_bytes, saslanonymous_get_mechanism_name.**]**

Просмотреть файл

@ -0,0 +1,90 @@
#sasl_frame_codec requirements
##Overview
sasl_frame_codec is module that encodes/decodes SASL frames per the AMQP ISO.
##Exposed API
```C
typedef struct SASL_FRAME_CODEC_INSTANCE_TAG* SASL_FRAME_CODEC_HANDLE;
typedef void(*SASL_FRAME_RECEIVED_CALLBACK)(void* context, AMQP_VALUE sasl_frame_value);
typedef void(*SASL_FRAME_CODEC_ERROR_CALLBACK)(void* context);
extern SASL_FRAME_CODEC_HANDLE sasl_frame_codec_create(FRAME_CODEC_HANDLE frame_codec, ON_SASL_FRAME_RECEIVED on_sasl_frame_received, ON_SASL_FRAME_CODEC_ERROR on_sasl_frame_codec_error, void* callback_context);
extern void sasl_frame_codec_destroy(SASL_FRAME_CODEC_HANDLE sasl_frame_codec);
extern int sasl_frame_codec_encode_frame(SASL_FRAME_CODEC_HANDLE sasl_frame_codec, const AMQP_VALUE sasl_frame_value, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context);
```
###sasl_frame_codec_create
```C
extern SASL_FRAME_CODEC_HANDLE sasl_frame_codec_create(FRAME_CODEC_HANDLE frame_codec, ON_SASL_FRAME_RECEIVED on_sasl_frame_received, ON_SASL_FRAME_CODEC_ERROR on_sasl_frame_codec_error, void* callback_context);
```
**SRS_SASL_FRAME_CODEC_01_018: [**sasl_frame_codec_create shall create an instance of an sasl_frame_codec and return a non-NULL handle to it.**]**
**SRS_SASL_FRAME_CODEC_01_019: [**If any of the arguments frame_codec, on_sasl_frame_received or on_sasl_frame_codec_error is NULL, sasl_frame_codec_create shall return NULL.**]**
**SRS_SASL_FRAME_CODEC_01_020: [**sasl_frame_codec_create shall subscribe for SASL frames with the given frame_codec.**]**
**SRS_SASL_FRAME_CODEC_01_021: [**If subscribing for SASL frames fails, sasl_frame_codec_create shall fail and return NULL.**]**
**SRS_SASL_FRAME_CODEC_01_022: [**sasl_frame_codec_create shall create a decoder to be used for decoding SASL values.**]**
**SRS_SASL_FRAME_CODEC_01_023: [**If creating the decoder fails, sasl_frame_codec_create shall fail and return NULL.**]**
**SRS_SASL_FRAME_CODEC_01_024: [**If allocating memory for the new sasl_frame_codec fails, then sasl_frame_codec_create shall fail and return NULL.**]**
###sasl_frame_codec_destroy
```C
extern void sasl_frame_codec_destroy(SASL_FRAME_CODEC_HANDLE sasl_frame_codec);
```
**SRS_SASL_FRAME_CODEC_01_025: [**sasl_frame_codec_destroy shall free all resources associated with the sasl_frame_codec instance.**]**
**SRS_SASL_FRAME_CODEC_01_026: [**If sasl_frame_codec is NULL, sasl_frame_codec_destroy shall do nothing.**]**
**SRS_SASL_FRAME_CODEC_01_027: [**sasl_frame_codec_destroy shall unsubscribe from receiving SASL frames from the frame_codec that was passed to sasl_frame_codec_create.**]**
**SRS_SASL_FRAME_CODEC_01_028: [**The decoder created in sasl_frame_codec_create shall be destroyed by sasl_frame_codec_destroy.**]**
###sasl_frame_codec_encode_frame
```C
extern int sasl_frame_codec_encode_frame(SASL_FRAME_CODEC_HANDLE sasl_frame_codec, const AMQP_VALUE sasl_frame_value, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context);
```
**SRS_SASL_FRAME_CODEC_01_029: [**sasl_frame_codec_encode_frame shall encode the frame header and sasl_frame_value AMQP value in a SASL frame and on success it shall return 0.**]**
**SRS_SASL_FRAME_CODEC_01_030: [**If sasl_frame_codec or sasl_frame_value is NULL, sasl_frame_codec_encode_frame shall fail and return a non-zero value.**]**
**SRS_SASL_FRAME_CODEC_01_031: [**sasl_frame_codec_encode_frame shall encode the frame header and its contents by using frame_codec_encode_frame.**]**
**SRS_SASL_FRAME_CODEC_01_032: [**The payload frame size shall be computed based on the encoded size of the sasl_frame_value and its fields.**]**
**SRS_SASL_FRAME_CODEC_01_033: [**The encoded size of the sasl_frame_value and its fields shall be obtained by calling amqpvalue_get_encoded_size.**]**
**SRS_SASL_FRAME_CODEC_01_034: [**If any error occurs during encoding, sasl_frame_codec_encode_frame shall fail and return a non-zero value.**]**
**SRS_SASL_FRAME_CODEC_01_035: [**Encoding of the sasl_frame_value and its fields shall be done by calling amqpvalue_encode.**]**
###Receive frames
**SRS_SASL_FRAME_CODEC_01_039: [**sasl_frame_codec shall decode the sasl-frame value as a described type.**]**
**SRS_SASL_FRAME_CODEC_01_040: [**Decoding the sasl-frame type shall be done by feeding the bytes to the decoder create in sasl_frame_codec_create.**]**
**SRS_SASL_FRAME_CODEC_01_041: [**Once the sasl frame is decoded, the callback on_sasl_frame_received shall be called.**]**
**SRS_SASL_FRAME_CODEC_01_042: [**The decoded sasl-frame value and the context passed in sasl_frame_codec_create shall be passed to on_sasl_frame_received.**]**
**SRS_SASL_FRAME_CODEC_01_046: [**If any error occurs while decoding a frame, the decoder shall switch to an error state where decoding shall not be possible anymore.**]**
**SRS_SASL_FRAME_CODEC_01_049: [**If any error occurs while decoding a frame, the decoder shall call the on_sasl_frame_codec_error and pass to it the callback_context, both of those being the ones given to sasl_frame_codec_create.**]**
##ISO section (receive)
5.3.1 SASL Frames
SASL performatives are framed as per Part 2: section 2.3. **SRS_SASL_FRAME_CODEC_01_001: [**A SASL frame has a type code of 0x01.**]** **SRS_SASL_FRAME_CODEC_01_006: [**Bytes 6 and 7 of the header are ignored.**]** Implementations SHOULD set these to 0x00. **SRS_SASL_FRAME_CODEC_01_007: [**The extended header is ignored.**]** Implementations SHOULD therefore set DOFF to 0x02.
...
Figure 5.5: SASL Frame
**SRS_SASL_FRAME_CODEC_01_008: [**The maximum size of a SASL frame is defined by MIN-MAX-FRAME-SIZE.**]** There is no mechanism within the SASL negotiation to negotiate a different size. **SRS_SASL_FRAME_CODEC_01_009: [**The frame body of a SASL frame MUST contain exactly one AMQP type, whose type encoding MUST have provides=“sasl-frame”.**]** **SRS_SASL_FRAME_CODEC_01_010: [**Receipt of an empty frame is an irrecoverable error.**]**
##ISO section (send)
5.3.1 SASL Frames
SASL performatives are framed as per Part 2: section 2.3. **SRS_SASL_FRAME_CODEC_01_011: [**A SASL frame has a type code of 0x01.**]** **SRS_SASL_FRAME_CODEC_01_012: [**Bytes 6 and 7 of the header are ignored.**]** **SRS_SASL_FRAME_CODEC_01_013: [**Implementations SHOULD set these to 0x00.**]** **SRS_SASL_FRAME_CODEC_01_014: [**The extended header is ignored.**]** **SRS_SASL_FRAME_CODEC_01_015: [**Implementations SHOULD therefore set DOFF to 0x02.**]**
...
Figure 5.5: SASL Frame
**SRS_SASL_FRAME_CODEC_01_016: [**The maximum size of a SASL frame is defined by MIN-MAX-FRAME-SIZE.**]** There is no mechanism within the SASL negotiation to negotiate a different size. **SRS_SASL_FRAME_CODEC_01_047: [**The frame body of a SASL frame MUST contain exactly one AMQP type, whose type encoding MUST have provides=“sasl-frame”.**]** Receipt of an empty frame is an irrecoverable error.

Просмотреть файл

@ -0,0 +1,81 @@
#sasl_mechanism requirements
##Overview
sasl_mechanism is a module that implements a SASL mechanism interface, abstracting from its consumers functionality of providing init bytes, handling the challenge and providing a response for it as part of the SASL negotiation.
##Exposed API
```C
typedef void* SASL_MECHANISM_HANDLE;
typedef void* CONCRETE_SASL_MECHANISM_HANDLE;
typedef struct INIT_BYTES_TAG
{
const void* bytes;
size_t length;
} INIT_BYTES;
typedef CONCRETE_SASL_MECHANISM_HANDLE(*SASL_MECHANISM_CREATE)(void* config);
typedef void(*SASL_MECHANISM_DESTROY)(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
typedef int(*SASL_MECHANISM_GET_INIT_BYTES)(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism, INIT_BYTES* init_bytes);
typedef const char*(*SASL_MECHANISM_GET_MECHANISM_NAME)(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
typedef struct SASL_MECHANISM_INTERFACE_TAG
{
SASL_MECHANISM_CREATE concrete_sasl_mechanism_create;
SASL_MECHANISM_DESTROY concrete_sasl_mechanism_destroy;
SASL_MECHANISM_GET_INIT_BYTES concrete_sasl_mechanism_get_init_bytes;
SASL_MECHANISM_GET_MECHANISM_NAME concrete_sasl_mechanism_get_mechanism_name;
} SASL_MECHANISM_INTERFACE_DESCRIPTION;
extern SASL_MECHANISM_HANDLE saslmechanism_create(const SASL_MECHANISM_INTERFACE_DESCRIPTION* sasl_mechanism_interface_description, void* sasl_mechanism_create_parameters, LOGGER_LOG logger_log);
extern void saslmechanism_destroy(SASL_MECHANISM_HANDLE sasl_mechanism);
extern int saslmechanism_get_init_bytes(SASL_MECHANISM_HANDLE sasl_mechanism, INIT_BYTES* init_bytes);
extern const char* saslmechanism_get_mechanism_name(SASL_MECHANISM_HANDLE sasl_mechanism);
```
###saslmechanism_create
```C
extern SASL_MECHANISM_HANDLE saslmechanism_create(const SASL_MECHANISM_INTERFACE_DESCRIPTION* sasl_mechanism_interface_description, void* sasl_mechanism_create_parameters);
```
**SRS_SASL_MECHANISM_01_001: [**saslmechanism_create shall return on success a non-NULL handle to a new SASL mechanism interface.**]**
**SRS_SASL_MECHANISM_01_002: [**In order to instantiate the concrete SASL mechanism implementation the function concrete_sasl_mechanism_create from the sasl_mechanism_interface_description shall be called, passing the sasl_mechanism_create_parameters to it.**]**
**SRS_SASL_MECHANISM_01_003: [**If the underlying concrete_sasl_mechanism_create call fails, saslmechanism_create shall return NULL.**]**
**SRS_SASL_MECHANISM_01_004: [**If the argument sasl_mechanism_interface_description is NULL, saslmechanism_create shall return NULL.**]**
**SRS_SASL_MECHANISM_01_005: [**If any sasl_mechanism_interface_description member is NULL, sasl_mechanism_create shall fail and return NULL.**]**
**SRS_SASL_MECHANISM_01_006: [**If allocating the memory needed for the SASL mechanism interface fails then saslmechanism_create shall fail and return NULL.**]**
###saslmechanism_destroy
```C
extern void saslmechanism_destroy(SASL_MECHANISM_HANDLE sasl_mechanism);
```
**SRS_SASL_MECHANISM_01_007: [**saslmechanism_destroy shall free all resources associated with the SASL mechanism handle.**]**
**SRS_SASL_MECHANISM_01_008: [**saslmechanism_destroy shall also call the concrete_sasl_mechanism_destroy function that is member of the sasl_mechanism_interface_description argument passed to saslmechanism_create, while passing as argument to concrete_sasl_mechanism_destroy the result of the underlying concrete SASL mechanism handle.**]**
**SRS_SASL_MECHANISM_01_009: [**If the argument sasl_mechanism is NULL, saslmechanism_destroy shall do nothing.**]**
###saslmechanism_get_init_bytes
```C
extern int saslmechanism_get_init_bytes(SASL_MECHANISM_HANDLE sasl_mechanism, INIT_BYTES* init_bytes);
```
**SRS_SASL_MECHANISM_01_010: [**saslmechanism_get_init_bytes shall call the specific concrete_sasl_mechanism_get_init_bytes function specified in saslmechanism_create, passing the init_bytes argument to it.**]**
**SRS_SASL_MECHANISM_01_011: [**On success, saslmechanism_get_init_bytes shall return 0.**]**
**SRS_SASL_MECHANISM_01_012: [**If the argument sasl_mechanism is NULL, saslmechanism_get_init_bytes shall fail and return a non-zero value.**]**
**SRS_SASL_MECHANISM_01_013: [**If the underlying concrete_sasl_mechanism_get_init_bytes fails, saslmechanism_get_init_bytes shall fail and return a non-zero value.**]**
###saslmechanism_get_mechanism_name
```C
extern const char* saslmechanism_get_mechanism_name(SASL_MECHANISM_HANDLE sasl_mechanism);
```
**SRS_SASL_MECHANISM_01_014: [**saslmechanism_get_mechanism_name shall call the specific concrete_sasl_mechanism_get_mechanism_name function specified in saslmechanism_create.**]**
**SRS_SASL_MECHANISM_01_015: [**On success, saslmechanism_get_mechanism_name shall return a pointer to a string with the mechanism name.**]**
**SRS_SASL_MECHANISM_01_016: [**If the argument sasl_mechanism is NULL, saslmechanism_get_mechanism_name shall fail and return a non-zero value.**]**
**SRS_SASL_MECHANISM_01_017: [**If the underlying concrete_sasl_mechanism_get_mechanism_name fails, saslmechanism_get_mechanism_name shall return NULL.**]**

Просмотреть файл

@ -0,0 +1,339 @@
#saslclientio requirements
##Overview
saslclientio is module that implements a concrete IO, that implements the section 5.3 of the AMQP ISO.
##Exposed API
```C
typedef struct SASLCLIENTIO_CONFIG_TAG
{
XIO_HANDLE underlying_io;
SASL_MECHANISM_HANDLE sasl_mechanism;
} SASLCLIENTIO_CONFIG;
extern CONCRETE_IO_HANDLE saslclientio_create(void* io_create_parameters, LOGGER_LOG logger_log);
extern void saslclientio_destroy(CONCRETE_IO_HANDLE sasl_client_io);
extern int saslclientio_open(CONCRETE_IO_HANDLE sasl_client_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context);
extern int saslclientio_close(CONCRETE_IO_HANDLE sasl_client_io);
extern int saslclientio_send(CONCRETE_IO_HANDLE sasl_client_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context);
extern void saslclientio_dowork(CONCRETE_IO_HANDLE sasl_client_io);
extern const IO_INTERFACE_DESCRIPTION* saslclientio_get_interface_description(void);
```
###saslclientio_create
```C
extern CONCRETE_IO_HANDLE saslclientio_create(void* io_create_parameters, LOGGER_LOG logger_log);
```
**SRS_SASLCLIENTIO_01_004: [**saslclientio_create shall return on success a non-NULL handle to a new SASL client IO instance.**]**
**SRS_SASLCLIENTIO_01_005: [**If xio_create_parameters is NULL, saslclientio_create shall fail and return NULL.**]**
**SRS_SASLCLIENTIO_01_006: [**If memory cannot be allocated for the new instance, saslclientio_create shall fail and return NULL.**]**
**SRS_SASLCLIENTIO_01_089: [**saslclientio_create shall create a frame_codec to be used for encoding/decoding frames bycalling frame_codec_create and passing the underlying_io as argument.**]**
**SRS_SASLCLIENTIO_01_090: [**If frame_codec_create fails, then saslclientio_create shall fail and return NULL.**]**
**SRS_SASLCLIENTIO_01_084: [**saslclientio_create shall create a sasl_frame_codec to be used for SASL frame encoding/decoding by calling sasl_frame_codec_create and passing the just created frame_codec as argument.**]**
**SRS_SASLCLIENTIO_01_085: [**If sasl_frame_codec_create fails, then saslclientio_create shall fail and return NULL.**]**
**SRS_SASLCLIENTIO_01_092: [**If any of the sasl_mechanism or underlying_io members of the configuration structure are NULL, saslclientio_create shall fail and return NULL.**]**
###saslclientio_destroy
```C
extern void saslclientio_destroy(CONCRETE_IO_HANDLE sasl_client_io);
```
**SRS_SASLCLIENTIO_01_007: [**saslclientio_destroy shall free all resources associated with the SASL client IO handle.**]**
**SRS_SASLCLIENTIO_01_086: [**saslclientio_destroy shall destroy the sasl_frame_codec created in saslclientio_create by calling sasl_frame_codec_destroy.**]**
**SRS_SASLCLIENTIO_01_091: [**saslclientio_destroy shall destroy the frame_codec created in saslclientio_create by calling frame_codec_destroy.**]**
**SRS_SASLCLIENTIO_01_008: [**If the argument sasl_client_io is NULL, saslclientio_destroy shall do nothing.**]**
###saslclientio_open
```C
extern int saslclientio_open(CONCRETE_IO_HANDLE sasl_client_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context);
```
**SRS_SASLCLIENTIO_01_009: [**saslclientio_open shall call xio_open on the underlying_io passed to saslclientio_create.**]**
**SRS_SASLCLIENTIO_01_010: [**On success, saslclientio_open shall return 0.**]**
**SRS_SASLCLIENTIO_01_011: [**If any of the sasl_client_io or on_bytes_received arguments is NULL, saslclientio_open shall fail and return a non-zero value.**]**
**SRS_SASLCLIENTIO_01_012: [**If the open of the underlying_io fails, saslclientio_open shall fail and return non-zero value.**]**
**SRS_SASLCLIENTIO_01_013: [**saslclientio_open shall pass to xio_open a callback for receiving bytes and a state changed callback for the underlying_io state changes.**]**
###saslclientio_close
```C
extern int saslclientio_close(CONCRETE_IO_HANDLE sasl_client_io);
```
**SRS_SASLCLIENTIO_01_015: [**saslclientio_close shall close the underlying io handle passed in saslclientio_create by calling xio_close.**]**
**SRS_SASLCLIENTIO_01_016: [**On success, saslclientio_close shall return 0.**]**
**SRS_SASLCLIENTIO_01_098: [**saslclientio_close shall only perform the close if the state is OPEN, OPENING or ERROR.**]**
**SRS_SASLCLIENTIO_01_097: [**If saslclientio_close is called when the IO is in the IO_STATE_NOT_OPEN state, no call to the underlying IO shall be made and saslclientio_close shall return 0.**]**
**SRS_SASLCLIENTIO_01_017: [**If sasl_client_io is NULL, saslclientio_close shall fail and return a non-zero value.**]**
**SRS_SASLCLIENTIO_01_018: [**If xio_close fails, then saslclientio_close shall return a non-zero value.**]**
###saslclientio_send
```C
extern int saslclientio_send(CONCRETE_IO_HANDLE sasl_client_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context);
```
**SRS_SASLCLIENTIO_01_019: [**If saslclientio_send is called while the SASL client IO state is not IO_STATE_OPEN, saslclientio_send shall fail and return a non-zero value.**]**
**SRS_SASLCLIENTIO_01_020: [**If the SASL client IO state is IO_STATE_OPEN, saslclientio_send shall call xio_send on the underlying_io passed to saslclientio_create, while passing as arguments the buffer, size, on_send_complete and callback_context.**]**
**SRS_SASLCLIENTIO_01_021: [**On success, saslclientio_send shall return 0.**]**
**SRS_SASLCLIENTIO_01_022: [**If the saslio or buffer argument is NULL, saslclientio_send shall fail and return a non-zero value.**]**
**SRS_SASLCLIENTIO_01_023: [**If size is 0, saslclientio_send shall fail and return a non-zero value.**]**
**SRS_SASLCLIENTIO_01_024: [**If the call to xio_send fails, then saslclientio_send shall fail and return a non-zero value.**]**
###saslclientio_dowork
```C
extern void saslclientio_dowork(CONCRETE_IO_HANDLE sasl_client_io);
```
**SRS_SASLCLIENTIO_01_025: [**saslclientio_dowork shall call the xio_dowork on the underlying_io passed in saslclientio_create.**]**
**SRS_SASLCLIENTIO_01_099: [**If the state of the IO is NOT_OPEN or ERROR, saslclientio_dowork shall make no calls to the underlying IO.**]**
**SRS_SASLCLIENTIO_01_026: [**If the sasl_client_io argument is NULL, saslclientio_dowork shall do nothing.**]**
###saslclientio_get_interface_description
```C
extern const IO_INTERFACE_DESCRIPTION* saslclientio_get_interface_description(void);
```
**SRS_SASLCLIENTIO_01_087: [**saslclientio_get_interface_description shall return a pointer to an IO_INTERFACE_DESCRIPTION structure that contains pointers to the functions: saslclientio_create, saslclientio_destroy, saslclientio_open, saslclientio_close, saslclientio_send and saslclientio_dowork.**]**
###on_bytes_received
**SRS_SASLCLIENTIO_01_027: [**When the on_bytes_received callback passed to the underlying IO is called and the SASL client IO state is IO_STATE_OPEN, the bytes shall be indicated to the user of SASL client IO by calling the on_bytes_received that was passed in saslclientio_open.**]**
**SRS_SASLCLIENTIO_01_028: [**If buffer is NULL or size is zero, nothing should be indicated as received and the saslio state shall be switched to ERROR the on_state_changed callback shall be triggered.**]**
**SRS_SASLCLIENTIO_01_029: [**The context argument shall be set to the callback_context passed in saslclientio_open.**]**
**SRS_SASLCLIENTIO_01_030: [**If bytes are received when the SASL client IO state is IO_STATE_OPENING, the bytes shall be consumed by the SASL client IO to satisfy the SASL handshake.**]**
**SRS_SASLCLIENTIO_01_031: [**If bytes are received when the SASL client IO state is IO_STATE_ERROR, SASL client IO shall do nothing.**]**
###on_state_changed
The following actions matrix shall be implemented when a new state change is received from the underlying IO:
| | new underlying IO state |
|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|SASL state|NOT_OPEN |OPENING |OPEN |ERROR |
|----------|--------------------------------------|----------------------------------------|------------------------------------------------|---------------------------------------|
|NOT_OPEN |**SRS_SASLCLIENTIO_01_115: [**do nothing**]** | **SRS_SASLCLIENTIO_01_108: [**do nothing**]** |**SRS_SASLCLIENTIO_01_104: [**do nothing**]** |**SRS_SASLCLIENTIO_01_100: [**do nothing**]** |
|OPENING |**SRS_SASLCLIENTIO_01_114: [**raise ERROR**]**| **SRS_SASLCLIENTIO_01_109: [**do nothing**]** |**SRS_SASLCLIENTIO_01_105: [**start header exchange**]**|**SRS_SASLCLIENTIO_01_101: [**raise ERROR**]** |
|OPEN |**SRS_SASLCLIENTIO_01_113: [**raise ERROR**]**| **SRS_SASLCLIENTIO_01_110: [**raise ERROR**]** |**SRS_SASLCLIENTIO_01_106: [**do nothing**]** |**SRS_SASLCLIENTIO_01_102: [**raise ERROR**]** |
|ERROR |**SRS_SASLCLIENTIO_01_112: [**do nothing**]** | **SRS_SASLCLIENTIO_01_111: [**do nothing**]** |**SRS_SASLCLIENTIO_01_107: [**do nothing**]** |**SRS_SASLCLIENTIO_01_103: [**do nothing**]** |
|----------|--------------------------------------|----------------------------------------|------------------------------------------------|---------------------------------------|
Starting the header exchange is done as follows:
**SRS_SASLCLIENTIO_01_078: [**SASL client IO shall start the header exchange by sending the SASL header.**]**
**SRS_SASLCLIENTIO_01_095: [**Sending the header shall be done by using xio_send.**]**
**SRS_SASLCLIENTIO_01_077: [**If sending the SASL header fails, the SASL client IO state shall be set to IO_STATE_ERROR and the on_state_changed callback shall be triggered.**]**
**SRS_SASLCLIENTIO_01_116: [**Any underlying IO state changes to state OPEN after the header exchange has been started shall trigger no action.**]**
###on_sasl_frame_received_callback
**SRS_SASLCLIENTIO_01_117: [**If on_sasl_frame_received_callback is called when the state of the IO is OPEN then the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.**]**
**SRS_SASLCLIENTIO_01_118: [**If on_sasl_frame_received_callback is called in the OPENING state but the header exchange has not yet been completed, then the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.**]**
When a frame is indicated as received by sasl_frame_codec it shall be processed as described in the ISO.
**SRS_SASLCLIENTIO_01_070: [**When a frame needs to be sent as part of the SASL handshake frame exchange, the send shall be done by calling sasl_frame_codec_encode_frame.**]**
**SRS_SASLCLIENTIO_01_071: [**If sasl_frame_codec_encode_frame fails, then the state of SASL client IO shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.**]**
**SRS_SASLCLIENTIO_01_072: [**When the SASL handshake is complete, if the handshake is successful, the SASL client IO state shall be switched to IO_STATE_OPEN and the on_state_changed callback shall be triggered.**]**
**SRS_SASLCLIENTIO_01_119: [**If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.**]**
**SRS_SASLCLIENTIO_01_073: [**If the handshake fails (i.e. the outcome is an error) the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.**]**
###on_bytes_encoded
**SRS_SASLCLIENTIO_01_120: [**When SASL client IO is notified by sasl_frame_codec of bytes that have been encoded via the on_bytes_encoded callback and SASL client IO is in the state OPENING, SASL client IO shall send these bytes by using xio_send.**]**
**SRS_SASLCLIENTIO_01_121: [**If xio_send fails, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.**]**
##SASL negotiation
**SRS_SASLCLIENTIO_01_067: [**The SASL frame exchange shall be started as soon as the SASL header handshake is done.**]**
**SRS_SASLCLIENTIO_01_068: [**During the SASL frame exchange that constitutes the handshake the received bytes from the underlying IO shall be fed to the frame_codec instance created in saslclientio_create by calling frame_codec_receive_bytes.**]**
**SRS_SASLCLIENTIO_01_088: [**If frame_codec_receive_bytes fails, the state of SASL client IO shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.**]**
##ISO section
**SRS_SASLCLIENTIO_01_001: [**To establish a SASL layer, each peer MUST start by sending a protocol header.**]**
**SRS_SASLCLIENTIO_01_002: [**The protocol header consists of the upper case ASCII letters “AMQP” followed by a protocol id of three, followed by three unsigned bytes representing the major, minor, and revision of the specification version (currently 1 (SASL-MAJOR), 0 (SASLMINOR), 0 (SASL-REVISION)).**]** In total this is an 8-octet sequence:
...
Figure 5.3: Protocol Header for SASL Security Layer
**SRS_SASLCLIENTIO_01_003: [**Other than using a protocol id of three, the exchange of SASL layer headers follows the same rules specified in the version negotiation section of the transport specification (See Part 2: section 2.2).**]**
The following diagram illustrates the interaction involved in creating a SASL security layer:
...
Figure 5.4: Establishing a SASL Security Layer
SASL Negotiation
**SRS_SASLCLIENTIO_01_032: [**The peer acting as the SASL server MUST announce supported authentication mechanisms using the sasl-mechanisms frame.**]**
**SRS_SASLCLIENTIO_01_033: [**The partner MUST then choose one of the supported mechanisms and initiate a sasl exchange.**]**
SASL Client SASL Server
**SRS_SASLCLIENTIO_01_034: [**<-- SASL-MECHANISMS**]**
**SRS_SASLCLIENTIO_01_035: [**SASL-INIT -->**]**
...
**SRS_SASLCLIENTIO_01_036: [**<-- SASL-CHALLENGE ***]**
**SRS_SASLCLIENTIO_01_037: [**SASL-RESPONSE -->**]**
...
**SRS_SASLCLIENTIO_01_038: [**<-- SASL-OUTCOME**]**
* Note that **SRS_SASLCLIENTIO_01_039: [**the SASL challenge/response step can occur zero or more times depending on the details of the SASL mechanism chosen.**]**
Figure 5.6: SASL Exchange
**SRS_SASLCLIENTIO_01_040: [**The peer playing the role of the SASL client and the peer playing the role of the SASL server MUST correspond to the TCP client and server respectively.**]**
5.3.3 Security Frame Bodies
5.3.3.1 SASL Mechanisms
Advertise available sasl mechanisms.
\<type name="sasl-mechanisms" class="composite" source="list" provides="sasl-frame">
\<descriptor name="amqp:sasl-mechanisms:list" code="0x00000000:0x00000040"/>
\<field name="sasl-server-mechanisms" type="symbol" multiple="true" mandatory="true"/>
\</type>
Advertises the available SASL mechanisms that can be used for authentication.
Field Details
sasl-server-mechanisms supported sasl mechanisms
**SRS_SASLCLIENTIO_01_041: [**A list of the sasl security mechanisms supported by the sending peer.**]** **SRS_SASLCLIENTIO_01_042: [**It is invalid for this list to be null or empty.**]** If the sending peer does not require its partner to authenticate with it, then it SHOULD send a list of one element with its value as the SASL mechanism ANONYMOUS. **SRS_SASLCLIENTIO_01_043: [**The server mechanisms are ordered in decreasing level of preference.**]**
5.3.3.2 SASL Init
Initiate sasl exchange.
\<type name="sasl-init" class="composite" source="list" provides="sasl-frame">
\<descriptor name="amqp:sasl-init:list" code="0x00000000:0x00000041"/>
\<field name="mechanism" type="symbol" mandatory="true"/>
\<field name="initial-response" type="binary"/>
\<field name="hostname" type="string"/>
\</type>
**SRS_SASLCLIENTIO_01_054: [**Selects the sasl mechanism and provides the initial response if needed.**]**
Field Details
mechanism selected security mechanism
**SRS_SASLCLIENTIO_01_045: [**The name of the SASL mechanism used for the SASL exchange.**]** If the selected mechanism is not supported by the receiving peer, it MUST close the connection with the authentication-failure close-code. **SRS_SASLCLIENTIO_01_046: [**Each peer MUST authenticate using the highest-level security profile it can handle from the list provided by the partner.**]**
initial-response security response data
**SRS_SASLCLIENTIO_01_047: [**A block of opaque data passed to the security mechanism.**]** **SRS_SASLCLIENTIO_01_048: [**The contents of this data are defined by the SASL security mechanism.**]**
hostname the name of the target host
**SRS_SASLCLIENTIO_01_049: [**The DNS name of the host (either fully qualified or relative) to which the sending peer is connecting.**]**
**SRS_SASLCLIENTIO_01_050: [**It is not mandatory to provide the hostname.**]** If no hostname is provided the receiving peer SHOULD select a default based on its own configuration.
This field can be used by AMQP proxies to determine the correct back-end service to connect the client to, and to determine the domain to validate the clients credentials against.
**SRS_SASLCLIENTIO_01_051: [**This field might already have been specified by the server name indication extension as described in RFC-4366 [RFC4366**]**, if a TLS layer is used, in which case this field SHOULD either be null or contain the same value.] It is undefined what a different value to those already specified means.
5.3.3.3 SASL Challenge
Security mechanism challenge.
\<type name="sasl-challenge" class="composite" source="list" provides="sasl-frame">
\<descriptor name="amqp:sasl-challenge:list" code="0x00000000:0x00000042"/>
\<field name="challenge" type="binary" mandatory="true"/>
\</type>
**SRS_SASLCLIENTIO_01_052: [**Send the SASL challenge data as defined by the SASL specification.**]**
Field Details
challenge security challenge data
**SRS_SASLCLIENTIO_01_053: [**Challenge information, a block of opaque binary data passed to the security mechanism.**]**
5.3.3.4 SASL Response
Security mechanism response.
\<type name="sasl-response" class="composite" source="list" provides="sasl-frame">
\<descriptor name="amqp:sasl-response:list" code="0x00000000:0x00000043"/>
\<field name="response" type="binary" mandatory="true"/>
\</type>
**SRS_SASLCLIENTIO_01_055: [**Send the SASL response data as defined by the SASL specification.**]**
Field Details
response security response data
**SRS_SASLCLIENTIO_01_056: [**A block of opaque data passed to the security mechanism.**]** **SRS_SASLCLIENTIO_01_057: [**The contents of this data are defined by the SASL security mechanism.**]**
5.3.3.5 SASL Outcome
Indicates the outcome of the sasl dialog.
\<type name="sasl-outcome" class="composite" source="list" provides="sasl-frame">
\<descriptor name="amqp:sasl-outcome:list" code="0x00000000:0x00000044"/>
\<field name="code" type="sasl-code" mandatory="true"/>
\<field name="additional-data" type="binary"/>
\</type>
**SRS_SASLCLIENTIO_01_058: [**This frame indicates the outcome of the SASL dialog.**]****SRS_SASLCLIENTIO_01_059: [**Upon successful completion of the SASL dialog the security layer has been established**]**, and the peers MUST exchange protocol headers to either start a nested security layer, or to establish the AMQP connection.
Field Details
code indicates the outcome of the sasl dialog
**SRS_SASLCLIENTIO_01_060: [**A reply-code indicating the outcome of the SASL dialog.**]**
additional-data additional data as specified in RFC-4422
**SRS_SASLCLIENTIO_01_061: [**The additional-data field carries additional data on successful authentication outcome as specified by the SASL specification [RFC4422**]**.] If the authentication is unsuccessful, this field is not set.
5.3.3.6 SASL Code
Codes to indicate the outcome of the sasl dialog.
\<type name="sasl-code" class="restricted" source="ubyte">
\<choice name="ok" value="0"/>
\<choice name="auth" value="1"/>
\<choice name="sys" value="2"/>
\<choice name="sys-perm" value="3"/>
\<choice name="sys-temp" value="4"/>
\</type>
Valid Values
**SRS_SASLCLIENTIO_01_062: [**0 Connection authentication succeeded.**]**
**SRS_SASLCLIENTIO_01_063: [**1 Connection authentication failed due to an unspecified problem with the supplied credentials.**]**
**SRS_SASLCLIENTIO_01_064: [**2 Connection authentication failed due to a system error.**]**
**SRS_SASLCLIENTIO_01_065: [**3 Connection authentication failed due to a system error that is unlikely to be corrected without intervention.**]**
**SRS_SASLCLIENTIO_01_066: [**4 Connection authentication failed due to a transient system error.**]**
5.3.4 Constant Definitions
**SRS_SASLCLIENTIO_01_124: [**SASL-MAJOR 1 major protocol version.**]**
**SRS_SASLCLIENTIO_01_125: [**SASL-MINOR 0 minor protocol version.**]**
**SRS_SASLCLIENTIO_01_126: [**SASL-REVISION 0 protocol revision.**]**

Просмотреть файл

@ -0,0 +1,407 @@
#session requirements
##Overview
session is module that implements the session layer in the AMQP ISO.
##Exposed API
```C
typedef void* SESSION_HANDLE;
typedef void* LINK_ENDPOINT_HANDLE;
typedef enum SESION_STATE_TAG
{
SESSION_STATE_UNMAPPED,
SESSION_STATE_BEGIN_SENT,
SESSION_STATE_BEGIN_RCVD,
SESSION_STATE_MAPPED,
SESSION_STATE_END_SENT,
SESSION_STATE_END_RCVD,
SESSION_STATE_DISCARDING
} SESSION_STATE;
typedef void(*LINK_ENDPOINT_FRAME_RECEIVED_CALLBACK)(void* context, AMQP_VALUE performative, uint32_t frame_payload_size, const unsigned char* payload_bytes);
typedef void(*ON_SESSION_STATE_CHANGED)(void* context, SESSION_STATE new_session_state, SESSION_STATE previous_session_state);
extern SESSION_HANDLE session_create(CONNECTION_HANDLE connection);
extern int session_set_incoming_window(SESSION_HANDLE session, uint32_t incoming_window);
extern int session_get_incoming_window(SESSION_HANDLE session, uint32_t* incoming_window);
extern int session_set_outgoing_window(SESSION_HANDLE session, uint32_t outgoing_window);
extern int session_get_outgoing_window(SESSION_HANDLE session, uint32_t* outgoing_window);
extern int session_set_handle_max(SESSION_HANDLE session, handle handle_max);
extern int session_get_handle_max(SESSION_HANDLE session, handle* handle_max);
extern void session_destroy(SESSION_HANDLE session);
extern LINK_ENDPOINT_HANDLE session_create_link_endpoint(SESSION_HANDLE session, const char* name, LINK_ENDPOINT_FRAME_RECEIVED_CALLBACK frame_received_callback, ON_SESSION_STATE_CHANGED on_session_state_changed, void* context);
extern int session_start_link_endpoint(LINK_ENDPOINT_HANDLE link_endpoint);
extern void session_destroy_link_endpoint(LINK_ENDPOINT_HANDLE link_endpoint);
extern int session_send_flow(LINK_ENDPOINT_HANDLE link_endpoint, FLOW_HANDLE flow);
extern int session_send_attach(LINK_ENDPOINT_HANDLE link_endpoint, ATTACH_HANDLE attach);
extern int session_send_detach(LINK_ENDPOINT_HANDLE link_endpoint, DETACH_HANDLE detach);
extern int session_send_transfer(LINK_ENDPOINT_HANDLE link_endpoint, TRANSFER_HANDLE transfer, PAYLOAD* payloads, size_t payload_count, delivery_number* delivery_id);
```
###session_create
```C
extern SESSION_HANDLE session_create(CONNECTION_HANDLE connection);
```
**SRS_SESSION_01_030: [**session_create shall create a new session instance and return a non-NULL handle to it.**]**
**SRS_SESSION_01_031: [**If connection is NULL, session_create shall fail and return NULL.**]**
**SRS_SESSION_01_032: [**session_create shall create a new session endpoint by calling connection_create_endpoint.**]**
**SRS_SESSION_01_033: [**If connection_create_endpoint fails, session_create shall fail and return NULL.**]**
**SRS_SESSION_01_042: [**If allocating memory for the session fails, session_create shall fail and return NULL.**]**
###session_destroy
```C
extern void session_destroy(SESSION_HANDLE session);
```
**SRS_SESSION_01_034: [**session_destroy shall free all resources allocated by session_create.**]**
**SRS_SESSION_01_035: [**The endpoint created in session_create shall be freed by calling connection_destroy_endpoint.**]**
**SRS_SESSION_01_036: [**If session is NULL, session_destroy shall do nothing.**]**
###session_create_link_endpoint
```C
extern LINK_ENDPOINT_HANDLE session_create_link_endpoint(SESSION_HANDLE session, const char* name, LINK_ENDPOINT_FRAME_RECEIVED_CALLBACK frame_received_callback, void* context);
```
**SRS_SESSION_01_043: [**session_create_link_endpoint shall create a link endpoint associated with a given session and return a non-NULL handle to it.**]**
**SRS_SESSION_01_044: [**If session, name or frame_received_callback is NULL, session_create_link_endpoint shall fail and return NULL.**]**
**SRS_SESSION_01_045: [**If allocating memory for the link endpoint fails, session_create_link_endpoint shall fail and return NULL.**]**
**SRS_SESSION_01_046: [**An unused handle shall be assigned to the link endpoint.**]**
**SRS_SESSION_01_047: [**The lowest available handle shall be used.**]**
**SRS_SESSION_01_048: [**If no more handles are available, session_create_link_endpoint shall fail and return NULL.**]**
###session_destroy_link_endpoint
```C
extern void session_destroy_link_endpoint(LINK_ENDPOINT_HANDLE link_endpoint);
```
**SRS_SESSION_01_049: [**session_destroy_link_endpoint shall free all resources associated with the endpoint.**]**
**SRS_SESSION_01_050: [**If link_endpoint is NULL, session_destroy_link_endpoint shall do nothing.**]**
###session_send_transfer
```C
extern int session_send_transfer(LINK_ENDPOINT_HANDLE link_endpoint, TRANSFER_HANDLE transfer, PAYLOAD* payloads, size_t payload_count, delivery_number* delivery_id);
```
**SRS_SESSION_01_051: [**session_send_transfer shall send a transfer frame with the performative indicated in the transfer argument.**]**
**SRS_SESSION_01_053: [**On success, session_send_transfer shall return 0.**]**
**SRS_SESSION_01_054: [**If link_endpoint or transfer is NULL, session_send_transfer shall fail and return a non-zero value.**]**
**SRS_SESSION_01_055: [**The encoding of the frame shall be done by calling connection_encode_frame and passing as arguments: the connection handle associated with the session, the transfer performative and the payload chunks passed to session_send_transfer.**]**
**SRS_SESSION_01_056: [**If connection_encode_frame fails then session_send_transfer shall fail and return a non-zero value.**]**
**SRS_SESSION_01_057: [**The delivery ids shall be assigned starting at 0.**]**
**SRS_SESSION_01_058: [**When any other error occurs, session_send_transfer shall fail and return a non-zero value.**]**
**SRS_SESSION_01_059: [**When session_send_transfer is called while the session is not in the MAPPED state, session_send_transfer shall fail and return a non-zero value.**]**
###connection_state_changed_callback
The following shall be done when the connection_state_changed_callback is triggered:
- **SRS_SESSION_01_060: [**If the previous connection state is not OPENED and the new connection state is OPENED, the BEGIN frame shall be sent out and the state shall be switched to BEGIN_SENT.**]**
- **SRS_SESSION_01_061: [**If the previous connection state is OPENED and the new connection state is not OPENED anymore, the state shall be switched to DISCARDING.**]**
##ISO section
Sessions
A session is a bidirectional sequential conversation between two containers that provides a grouping for related links. Sessions serve as the context for link communication. Any number of links of any directionality can be attached to a given session. However, a link MUST NOT be attached to more than one session at a time.
...
Figure 2.25: Instance Diagram of Session/Link attachment
Messages transferred on a link are sequentially identified within the session. A session can be viewed as multiplexing link traffic, much like a connection multiplexes session traffic. However, unlike the sessions on a connection, links on a session are not entirely independent since they share a common delivery sequence scoped to the session.
This common sequence allows endpoints to efficiently refer to sets of deliveries regardless of the originating link. This is of particular benefit when a single application is receiving messages along a large number of different links. In this case the session provides aggregation of otherwise independent links into a single stream that can be efficiently acknowledged by the receiving application.
2.5.1 Establishing A Session
**SRS_SESSION_01_001: [**Sessions are established by creating a session endpoint, assigning it to an unused channel number, and sending a begin announcing the association of the session endpoint with the outgoing channel.**]** **SRS_SESSION_01_002: [**Upon receiving the begin the partner will check the remote-channel field and find it empty.**]** This indicates that the begin is referring to remotely initiated session. **SRS_SESSION_01_003: [**The partner will therefore allocate an unused outgoing channel for the remotely initiated session and indicate this by sending its own begin setting the remote-channel field to the incoming channel of the remotely initiated session.**]**
**SRS_SESSION_01_004: [**To make it easier to monitor AMQP sessions, it is RECOMMENDED that implementations always assign the lowest available unused channel number.**]**
**SRS_SESSION_01_005: [**The remote-channel field of a begin frame MUST be empty for a locally initiated session**]**,**SRS_SESSION_01_006: [**and MUST be set when announcing the endpoint created as a result of a remotely initiated session.**]**
...
Figure 2.26: Session Begin Sequence
2.5.2 Ending A Session
**SRS_SESSION_01_007: [**Sessions end automatically when the connection is closed or interrupted.**]** **SRS_SESSION_01_008: [**Sessions are explicitly ended when either endpoint chooses to end the session.**]** **SRS_SESSION_01_009: [**When a session is explicitly ended, an end frame is sent to announce the disassociation of the endpoint from its outgoing channel, and to carry error information when relevant.**]**
...
Figure 2.27: Session End Sequence
2.5.3 Simultaneous End
Due to the potentially asynchronous nature of sessions, it is possible that both peers simultaneously decide to end a session. If this happens, it will appear to each peer as though their partners spontaneously initiated end frame is actually an answer to the peers initial end frame.
...
Figure 2.28: Simultaneous Session End Sequence
2.5.4 Session Errors
**SRS_SESSION_01_010: [**When a session is unable to process input, it MUST indicate this by issuing an END with an appropriate error indicating the cause of the problem.**]** **SRS_SESSION_01_011: [**It MUST then proceed to discard all incoming frames from the remote endpoint until receiving the remote endpoints corresponding end frame.**]**
...
Figure 2.29: Session Error Sequence
2.5.5 Session States
UNMAPPED In the UNMAPPED state, the session endpoint is not mapped to any incoming or outgoing channels on the connection endpoint. In this state an endpoint cannot send or receive frames.
BEGIN SENT In the BEGIN SENT state, the session endpoint is assigned an outgoing channel number, but there is no entry in the incoming channel map. In this state the endpoint MAY send frames but cannot receive them.
BEGIN RCVD In the BEGIN RCVD state, the session endpoint has an entry in the incoming channel map, but has not yet been assigned an outgoing channel number. The endpoint MAY receive frames, but cannot send them.
MAPPED In the MAPPED state, the session endpoint has both an outgoing channel number and an entry in the incoming channel map. The endpoint MAY both send and receive frames.
END SENT In the END SENT state, the session endpoint has an entry in the incoming channel map, but is no longer assigned an outgoing channel number. The endpoint MAY receive frames, but cannot send them.
END RCVD In the END RCVD state, the session endpoint is assigned an outgoing channel number, but there is no entry in the incoming channel map. The endpoint MAY send frames, but cannot receive them.
DISCARDING The DISCARDING state is a variant of the END SENT state where the end is triggered by an error. In this case any incoming frames on the session MUST be silently discarded until the peers end frame is received.
...
Figure 2.30: State Transitions
There is no obligation to retain a session endpoint after it transitions to the UNMAPPED state.
2.5.6 Session Flow Control
**SRS_SESSION_01_012: [**The session endpoint assigns each outgoing transfer frame an implicit transfer-id from a session scoped sequence.**]****SRS_SESSION_01_013: [**Each session endpoint maintains the following state to manage incoming and outgoing transfer frames**]** :
**SRS_SESSION_01_014: [**next-incoming-id The next-incoming-id identifies the expected transfer-id of the next incoming transfer frame.**]**
**SRS_SESSION_01_015: [**incoming-window The incoming-window defines the maximum number of incoming transfer frames that the endpoint can currently receive.**]** This identifies a current maximum incoming transfer-id that can be computed by subtracting one from the sum of incoming-window and next-incomingid.
**SRS_SESSION_01_016: [**next-outgoing-id The next-outgoing-id is the transfer-id to assign to the next transfer frame.**]** **SRS_SESSION_01_017: [**The nextoutgoing-id MAY be initialized to an arbitrary value **]** and **SRS_SESSION_01_018: [**is incremented after each successive transfer according to RFC-1982 [RFC1982**]** serial number arithmetic.]
**SRS_SESSION_01_019: [**outgoing-window The outgoing-window defines the maximum number of outgoing transfer frames that the endpoint can currently send.**]** This identifies a current maximum outgoing transfer-id that can be computed by subtracting one from the sum of outgoing-window and next-outgoing-id.
**SRS_SESSION_01_020: [**remote-incoming-window The remote-incoming-window reflects the maximum number of outgoing transfers that can be sent without exceeding the remote endpoints incoming-window.**]****SRS_SESSION_01_021: [**This value MUST be decremented after every transfer frame is sent**]**,**SRS_SESSION_01_022: [**and recomputed when informed of the remote session endpoint state.**]**
**SRS_SESSION_01_023: [**remote-outgoing-window The remote-outgoing-window reflects the maximum number of incoming transfers that MAY arrive without exceeding the remote endpoints outgoing-window.**]****SRS_SESSION_01_024: [**This value MUST be decremented after every incoming transfer frame is received**]**, **SRS_SESSION_01_025: [**and recomputed when informed of the remote session endpoint state.**]** When this window shrinks, it is an indication of outstanding transfers. Settling outstanding transfers can cause the window to grow.
**SRS_SESSION_01_026: [**Once initialized, this state is updated by various events that occur in the lifespan of a session and its associated links:**]**
**SRS_SESSION_01_027: [**sending a transfer Upon sending a transfer, the sending endpoint will increment its next-outgoing-id**]**, **SRS_SESSION_01_062: [**decrement its remote-incoming-window**]** ,**SRS_SESSION_01_063: [**and MAY (depending on policy) decrement its outgoing window**]** .
**SRS_SESSION_01_028: [**receiving a transfer Upon receiving a transfer, the receiving endpoint will increment the next-incoming-id to match the implicit transfer-id of the incoming transfer plus one, as well as decrementing the remote-outgoing-window, and MAY (depending on policy) decrement its incoming-window.**]**
**SRS_SESSION_01_029: [**receiving a flow When the endpoint receives a flow frame from its peer, it MUST update the next-incoming-id directly from the next-outgoing-id of the frame, and it MUST update the remote-outgoingwindow directly from the outgoing-window of the frame.**]**
The remote-incoming-window is computed as follows:
next-incoming-idow + incoming-windowow - next-outgoing-idendpoint
If the next-incoming-id field of the flow frame is not set, then remote-incoming-window is computed as follows:
initial-outgoing-idendpoint + incoming-windowow - next-outgoing-idendpoint
Begin frame
2.7.2 Begin
Begin a session on a channel.
\<type name="begin" class="composite" source="list" provides="frame">
\<descriptor name="amqp:begin:list" code="0x00000000:0x00000011"/>
\<field name="remote-channel" type="ushort"/>
\<field name="next-outgoing-id" type="transfer-number" mandatory="true"/>
\<field name="incoming-window" type="uint" mandatory="true"/>
\<field name="outgoing-window" type="uint" mandatory="true"/>
\<field name="handle-max" type="handle" default="4294967295"/>
\<field name="offered-capabilities" type="symbol" multiple="true"/>
\<field name="desired-capabilities" type="symbol" multiple="true"/>
\<field name="properties" type="fields"/>
\</type>
Indicate that a session has begun on the channel.
Field Details
remote-channel the remote channel for this session
If a session is locally initiated, the remote-channel MUST NOT be set. When an endpoint responds
to a remotely initiated session, the remote-channel MUST be set to the channel on which the
remote session sent the begin.
next-outgoing-id the transfer-id of the first transfer id the sender will send
See subsection 2.5.6.
incoming-window the initial incoming-window of the sender
See subsection 2.5.6.
outgoing-window the initial outgoing-window of the sender
See subsection 2.5.6.
handle-max the maximum handle value that can be used on the session
The handle-max value is the highest handle value that can be used on the session. A peer MUST
NOT attempt to attach a link using a handle value outside the range that its partner can handle.
A peer that receives a handle outside the supported range MUST close the connection with the
framing-error error-code.
offered-capabilities the extension capabilities the sender supports
A registry of commonly defined session capabilities and their meanings is maintained
[AMQPSESSCAP].
desired-capabilities the extension capabilities the sender can use if the receiver supports them
The sender MUST NOT attempt to use any capability other than those it has declared in desiredcapabilities
field.
properties session properties
The properties map contains a set of fields intended to indicate information about the session and
its container.
A registry of commonly defined session properties and their meanings is maintained
[AMQPSESSPROP].
Transfer frame
2.7.5 Transfer
Transfer a message.
\<type name="transfer" class="composite" source="list" provides="frame">
\<descriptor name="amqp:transfer:list" code="0x00000000:0x00000014"/>
\<field name="handle" type="handle" mandatory="true"/>
\<field name="delivery-id" type="delivery-number"/>
\<field name="delivery-tag" type="delivery-tag"/>
\<field name="message-format" type="message-format"/>
\<field name="settled" type="boolean"/>
\<field name="more" type="boolean" default="false"/>
\<field name="rcv-settle-mode" type="receiver-settle-mode"/>
\<field name="state" type="*" requires="delivery-state"/>
\<field name="resume" type="boolean" default="false"/>
\<field name="aborted" type="boolean" default="false"/>
\<field name="batchable" type="boolean" default="false"/>
\</type>
The transfer frame is used to send messages across a link. Messages MAY be carried by a single transfer up to the maximum negotiated frame size for the connection. Larger messages MAY be split across several transfer frames.
Field Details
handle
Specifies the link on which the message is transferred.
delivery-id alias for delivery-tag
The delivery-id MUST be supplied on the first transfer of a multi-transfer delivery. On continuation
transfers the delivery-id MAY be omitted. It is an error if the delivery-id on a continuation transfer
differs from the delivery-id on the first transfer of a delivery.
delivery-tag
Uniquely identifies the delivery attempt for a given message on this link. This field MUST be
specified for the first transfer of a multi-transfer message and can only be omitted for continuation
transfers. It is an error if the delivery-tag on a continuation transfer differs from the delivery-tag on
the first transfer of a delivery.
message-format indicates the message format
This field MUST be specified for the first transfer of a multi-transfer message and can only be
omitted for continuation transfers. It is an error if the message-format on a continuation transfer
differs from the message-format on the first transfer of a delivery.
settled
If not set on the first (or only) transfer for a (multi-transfer) delivery, then the settled flag MUST be
interpreted as being false. For subsequent transfers in a multi-transfer delivery if the settled flag
is left unset then it MUST be interpreted as true if and only if the value of the settled flag on any
of the preceding transfers was true; if no preceding transfer was sent with settled being true then
the value when unset MUST be taken as false.
If the negotiated value for snd-settle-mode at attachment is settled, then this field MUST be true
on at least one transfer frame for a delivery (i.e., the delivery MUST be settled at the sender at
the point the delivery has been completely transferred).
If the negotiated value for snd-settle-mode at attachment is unsettled, then this field MUST be
false (or unset) on every transfer frame for a delivery (unless the delivery is aborted).
more indicates that the message has more content
Note that if both the more and aborted fields are set to true, the aborted flag takes precedence.
That is, a receiver SHOULD ignore the value of the more field if the transfer is marked as aborted.
A sender SHOULD NOT set the more flag to true if it also sets the aborted flag to true.
rcv-settle-mode
If first, this indicates that the receiver MUST settle the delivery once it has arrived without waiting
for the sender to settle first.
If second, this indicates that the receiver MUST NOT settle until sending its disposition to the
sender and receiving a settled disposition from the sender.
If not set, this value is defaulted to the value negotiated on link attach.
If the negotiated link value is first, then it is illegal to set this field to second.
If the message is being sent settled by the sender, the value of this field is ignored.
The (implicit or explicit) value of this field does not form part of the transfer state, and is not
retained if a link is suspended and subsequently resumed.
state the state of the delivery at the sender
When set this informs the receiver of the state of the delivery at the sender. This is particularly
useful when transfers of unsettled deliveries are resumed after resuming a link. Setting the state
on the transfer can be thought of as being equivalent to sending a disposition immediately before
the transfer performative, i.e., it is the state of the delivery (not the transfer) that existed at the
point the frame was sent.
Note that if the transfer performative (or an earlier disposition performative referring to the
delivery) indicates that the delivery has attained a terminal state, then no future transfer or
disposition sent by the sender can alter that terminal state.
resume indicates a resumed delivery
If true, the resume flag indicates that the transfer is being used to reassociate an unsettled delivery
from a dissociated link endpoint. See subsection 2.6.13 for more details.
The receiver MUST ignore resumed deliveries that are not in its local unsettled map. The sender
MUST NOT send resumed transfers for deliveries not in its local unsettled map.
If a resumed delivery spans more than one transfer performative, then the resume flag MUST be
set to true on the first transfer of the resumed delivery. For subsequent transfers for the same
delivery the resume flag MAY be set to true, or MAY be omitted.
In the case where the exchange of unsettled maps makes clear that all message data has been
successfully transferred to the receiver, and that only the final state (and potentially settlement) at
the sender needs to be conveyed, then a resumed delivery MAY carry no payload and instead act
solely as a vehicle for carrying the terminal state of the delivery at the sender.
aborted indicates that the message is aborted
Aborted messages SHOULD be discarded by the recipient (any payload within the frame carrying
the performative MUST be ignored). An aborted message is implicitly settled.
batchable batchable hint
If true, then the issuer is hinting that there is no need for the peer to urgently communicate
updated delivery state. This hint MAY be used to artificially increase the amount of batching
an implementation uses when communicating delivery states, and thereby save bandwidth.
If the message being delivered is too large to fit within a single frame, then the setting of batchable
to true on any of the transfer performatives for the delivery is equivalent to setting batchable to
true for all the transfer performatives for the delivery.
The batchable value does not form part of the transfer state, and is not retained if a link is suspended
and subsequently resumed.

1032
inc/amqp_definitions.h Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

42
inc/amqp_frame_codec.h Normal file
Просмотреть файл

@ -0,0 +1,42 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef AMQP_FRAME_CODEC_H
#define AMQP_FRAME_CODEC_H
#ifdef __cplusplus
extern "C" {
#include <cstdint>
#include <cstddef>
#else
#include <stdint.h>
#include <stddef.h>
#endif /* __cplusplus */
#include "frame_codec.h"
#define AMQP_OPEN (uint64_t)0x10
#define AMQP_BEGIN (uint64_t)0x11
#define AMQP_ATTACH (uint64_t)0x12
#define AMQP_FLOW (uint64_t)0x13
#define AMQP_TRANSFER (uint64_t)0x14
#define AMQP_DISPOSITION (uint64_t)0x15
#define AMQP_DETACH (uint64_t)0x16
#define AMQP_END (uint64_t)0x17
#define AMQP_CLOSE (uint64_t)0x18
typedef struct AMQP_FRAME_CODEC_INSTANCE_TAG* AMQP_FRAME_CODEC_HANDLE;
typedef void(*AMQP_EMPTY_FRAME_RECEIVED_CALLBACK)(void* context, uint16_t channel);
typedef void(*AMQP_FRAME_RECEIVED_CALLBACK)(void* context, uint16_t channel, AMQP_VALUE performative, const unsigned char* payload_bytes, uint32_t frame_payload_size);
typedef void(*AMQP_FRAME_CODEC_ERROR_CALLBACK)(void* context);
extern AMQP_FRAME_CODEC_HANDLE amqp_frame_codec_create(FRAME_CODEC_HANDLE frame_codec, AMQP_FRAME_RECEIVED_CALLBACK frame_received_callback,
AMQP_EMPTY_FRAME_RECEIVED_CALLBACK empty_frame_received_callback, AMQP_FRAME_CODEC_ERROR_CALLBACK amqp_frame_codec_error_callback, void* callback_context);
extern void amqp_frame_codec_destroy(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec);
extern int amqp_frame_codec_encode_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel, const AMQP_VALUE performative, const PAYLOAD* payloads, size_t payload_count, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context);
extern int amqp_frame_codec_encode_empty_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* AMQP_FRAME_CODEC_H */

43
inc/amqp_management.h Normal file
Просмотреть файл

@ -0,0 +1,43 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef AMQPMAN_H
#define AMQPMAN_H
#include "session.h"
#include "message.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef enum OPERATION_RESULT_TAG
{
OPERATION_RESULT_OK,
OPERATION_RESULT_CBS_ERROR,
OPERATION_RESULT_OPERATION_FAILED
} OPERATION_RESULT;
typedef enum AMQP_MANAGEMENT_STATE_TAG
{
AMQP_MANAGEMENT_STATE_IDLE,
AMQP_MANAGEMENT_STATE_OPENING,
AMQP_MANAGEMENT_STATE_OPEN,
AMQP_MANAGEMENT_STATE_ERROR
} AMQP_MANAGEMENT_STATE;
typedef struct AMQP_MANAGEMENT_INSTANCE_TAG* AMQP_MANAGEMENT_HANDLE;
typedef void(*ON_OPERATION_COMPLETE)(void* context, OPERATION_RESULT operation_result, unsigned int status_code, const char* status_description);
typedef void(*ON_AMQP_MANAGEMENT_STATE_CHANGED)(void* context, AMQP_MANAGEMENT_STATE new_amqp_management_state, AMQP_MANAGEMENT_STATE previous_amqp_management_state);
extern AMQP_MANAGEMENT_HANDLE amqpmanagement_create(SESSION_HANDLE session, const char* management_node, ON_AMQP_MANAGEMENT_STATE_CHANGED on_amqp_management_state_changed, void* callback_context);
extern void amqpmanagement_destroy(AMQP_MANAGEMENT_HANDLE amqp_management);
extern int amqpmanagement_open(AMQP_MANAGEMENT_HANDLE amqp_management);
extern int amqpmanagement_close(AMQP_MANAGEMENT_HANDLE amqp_management);
extern int amqpmanagement_start_operation(AMQP_MANAGEMENT_HANDLE amqp_management, const char* operation, const char* type, const char* locales, MESSAGE_HANDLE message, ON_OPERATION_COMPLETE on_operation_complete, void* context);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* AMQPMAN_H */

45
inc/amqp_types.h Normal file
Просмотреть файл

@ -0,0 +1,45 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef ANQP_TYPES_H
#define ANQP_TYPES_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef enum AMQP_TYPE_TAG
{
AMQP_TYPE_NULL,
AMQP_TYPE_BOOL,
AMQP_TYPE_UBYTE,
AMQP_TYPE_USHORT,
AMQP_TYPE_UINT,
AMQP_TYPE_ULONG,
AMQP_TYPE_BYTE,
AMQP_TYPE_SHORT,
AMQP_TYPE_INT,
AMQP_TYPE_LONG,
AMQP_TYPE_FLOAT,
AMQP_TYPE_DOUBLE,
AMQP_TYPE_CHAR,
AMQP_TYPE_TIMESTAMP,
AMQP_TYPE_UUID,
AMQP_TYPE_BINARY,
AMQP_TYPE_STRING,
AMQP_TYPE_SYMBOL,
AMQP_TYPE_LIST,
AMQP_TYPE_MAP,
AMQP_TYPE_ARRAY,
AMQP_TYPE_DESCRIBED,
AMQP_TYPE_COMPOSITE,
AMQP_TYPE_UNKNOWN
} AMQP_TYPE;
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* ANQP_TYPES_H */

38
inc/amqpalloc.h Normal file
Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef AMQP_ALLOC_H
#define AMQP_ALLOC_H
#ifdef __cplusplus
extern "C" {
#include <cstddef>
#include <cstdbool>
#include <cstdlib>
#else
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#endif /* __cplusplus */
#ifndef DISABLE_MEMORY_TRACE
extern void* amqpalloc_malloc(size_t size);
extern void amqpalloc_free(void* ptr);
extern void* amqpalloc_calloc(size_t nmemb, size_t size);
extern void* amqpalloc_realloc(void* ptr, size_t size);
#else
#define amqpalloc_malloc malloc
#define amqpalloc_free free
#define amqpalloc_calloc calloc
#define amqpalloc_realloc realloc
#endif
extern size_t amqpalloc_get_maximum_memory_used(void);
extern size_t amqpalloc_get_current_memory_used(void);
extern void amqpalloc_set_memory_tracing_enabled(bool memory_tracing_enabled);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* AMQP_ALLOC_H */

120
inc/amqpvalue.h Normal file
Просмотреть файл

@ -0,0 +1,120 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef ANQPVALUE_H
#define ANQPVALUE_H
#include "amqp_types.h"
#ifdef __cplusplus
extern "C" {
#include <cstddef>
#include <cstdint>
#include <cstdbool>
#else
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#endif /* __cplusplus */
typedef struct AMQP_VALUE_DATA_TAG* AMQP_VALUE;
typedef unsigned char uuid[16];
typedef int64_t timestamp;
typedef struct amqp_binary_TAG
{
const void* bytes;
uint32_t length;
} amqp_binary;
/* type handling */
extern AMQP_VALUE amqpvalue_create_null(void);
extern AMQP_VALUE amqpvalue_create_boolean(bool value);
extern int amqpvalue_get_boolean(AMQP_VALUE value, bool* bool_value);
extern AMQP_VALUE amqpvalue_create_ubyte(unsigned char value);
extern int amqpvalue_get_ubyte(AMQP_VALUE value, unsigned char* ubyte_value);
extern AMQP_VALUE amqpvalue_create_ushort(uint16_t value);
extern int amqpvalue_get_ushort(AMQP_VALUE value, uint16_t* ushort_value);
extern AMQP_VALUE amqpvalue_create_uint(uint32_t value);
extern int amqpvalue_get_uint(AMQP_VALUE value, uint32_t* uint_value);
extern AMQP_VALUE amqpvalue_create_ulong(uint64_t value);
extern int amqpvalue_get_ulong(AMQP_VALUE value, uint64_t* ulong_value);
extern AMQP_VALUE amqpvalue_create_byte(char value);
extern int amqpvalue_get_byte(AMQP_VALUE value, char* byte_value);
extern AMQP_VALUE amqpvalue_create_short(int16_t value);
extern int amqpvalue_get_short(AMQP_VALUE value, int16_t* short_value);
extern AMQP_VALUE amqpvalue_create_int(int32_t value);
extern int amqpvalue_get_int(AMQP_VALUE value, int32_t* int_value);
extern AMQP_VALUE amqpvalue_create_long(int64_t value);
extern int amqpvalue_get_long(AMQP_VALUE value, int64_t* long_value);
extern AMQP_VALUE amqpvalue_create_float(float value);
extern int amqpvalue_get_float(AMQP_VALUE value, float* float_value);
extern AMQP_VALUE amqpvalue_create_double(double value);
extern int amqpvalue_get_double(AMQP_VALUE value, double* double_value);
extern AMQP_VALUE amqpvalue_create_char(uint32_t value);
extern int amqpvalue_get_char(AMQP_VALUE value, uint32_t* char_value);
extern AMQP_VALUE amqpvalue_create_timestamp(int64_t value);
extern int amqpvalue_get_timestamp(AMQP_VALUE value, int64_t* timestamp_value);
extern AMQP_VALUE amqpvalue_create_uuid(uuid value);
extern int amqpvalue_get_uuid(AMQP_VALUE value, uuid* uuid_value);
extern AMQP_VALUE amqpvalue_create_binary(amqp_binary value);
extern int amqpvalue_get_binary(AMQP_VALUE value, amqp_binary* binary_value);
extern AMQP_VALUE amqpvalue_create_string(const char* value);
extern int amqpvalue_get_string(AMQP_VALUE value, const char** string_value);
extern AMQP_VALUE amqpvalue_create_symbol(const char* value);
extern int amqpvalue_get_symbol(AMQP_VALUE value, const char** symbol_value);
extern AMQP_VALUE amqpvalue_create_list(void);
extern int amqpvalue_set_list_item_count(AMQP_VALUE value, uint32_t count);
extern int amqpvalue_get_list_item_count(AMQP_VALUE value, uint32_t* count);
extern int amqpvalue_set_list_item(AMQP_VALUE value, uint32_t index, AMQP_VALUE list_item_value);
extern AMQP_VALUE amqpvalue_get_list_item(AMQP_VALUE value, size_t index);
extern AMQP_VALUE amqpvalue_create_map(void);
extern int amqpvalue_set_map_value(AMQP_VALUE map, AMQP_VALUE key, AMQP_VALUE value);
extern AMQP_VALUE amqpvalue_get_map_value(AMQP_VALUE map, AMQP_VALUE key);
extern int amqpvalue_get_map_pair_count(AMQP_VALUE map, uint32_t* pair_count);
extern int amqpvalue_get_map_key_value_pair(AMQP_VALUE map, uint32_t index, AMQP_VALUE* key, AMQP_VALUE* value);
extern int amqpvalue_get_map(AMQP_VALUE value, AMQP_VALUE* map_value);
extern AMQP_TYPE amqpvalue_get_type(AMQP_VALUE value);
extern void amqpvalue_destroy(AMQP_VALUE value);
extern bool amqpvalue_are_equal(AMQP_VALUE value1, AMQP_VALUE value2);
extern AMQP_VALUE amqpvalue_clone(AMQP_VALUE value);
/* encoding */
typedef int(*AMQPVALUE_ENCODER_OUTPUT)(void* context, const unsigned char* bytes, size_t length);
extern int amqpvalue_encode(AMQP_VALUE value, AMQPVALUE_ENCODER_OUTPUT encoder_output, void* context);
extern int amqpvalue_get_encoded_size(AMQP_VALUE value, size_t* encoded_size);
/* decoding */
typedef void* AMQPVALUE_DECODER_HANDLE;
typedef void(*ON_VALUE_DECODED)(void* context, AMQP_VALUE decoded_value);
extern AMQPVALUE_DECODER_HANDLE amqpvalue_decoder_create(ON_VALUE_DECODED on_value_decoded, void* callback_context);
extern void amqpvalue_decoder_destroy(AMQPVALUE_DECODER_HANDLE handle);
extern int amqpvalue_decode_bytes(AMQPVALUE_DECODER_HANDLE handle, const unsigned char* buffer, size_t size);
/* misc for now */
extern AMQP_VALUE amqpvalue_create_array(void);
extern int amqpvalue_get_array_item_count(AMQP_VALUE value, uint32_t* count);
extern int amqpvalue_add_array_item(AMQP_VALUE value, AMQP_VALUE array_item_value);
extern AMQP_VALUE amqpvalue_get_array_item(AMQP_VALUE value, uint32_t index);
extern int amqpvalue_get_array(AMQP_VALUE value, AMQP_VALUE* array_value);
extern AMQP_VALUE amqpvalue_get_inplace_descriptor(AMQP_VALUE value);
extern AMQP_VALUE amqpvalue_get_inplace_described_value(AMQP_VALUE value);
extern AMQP_VALUE amqpvalue_create_composite(AMQP_VALUE descriptor, uint32_t list_size);
extern int amqpvalue_set_composite_item(AMQP_VALUE value, size_t index, AMQP_VALUE item_value);
extern AMQP_VALUE amqpvalue_get_composite_item(AMQP_VALUE value, size_t index);
extern AMQP_VALUE amqpvalue_create_described(AMQP_VALUE descriptor, AMQP_VALUE value);
extern AMQP_VALUE amqpvalue_create_composite_with_ulong_descriptor(uint64_t descriptor);
extern AMQP_VALUE amqpvalue_get_list_item_in_place(AMQP_VALUE value, size_t index);
extern AMQP_VALUE amqpvalue_get_composite_item_in_place(AMQP_VALUE value, size_t index);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* ANQPVALUE_H */

18
inc/amqpvalue_to_string.h Normal file
Просмотреть файл

@ -0,0 +1,18 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef AMQPVALUE_TO_STRING_H
#include "amqpvalue.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern char* amqpvalue_to_string(AMQP_VALUE amqp_value);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* AMQPVALUE_TO_STRING_H */

35
inc/cbs.h Normal file
Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef CBS_H
#define CBS_H
#include "session.h"
#include "amqp_management.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef enum CBS_OPERATION_RESULT_TAG
{
CBS_OPERATION_RESULT_OK,
CBS_OPERATION_RESULT_CBS_ERROR,
CBS_OPERATION_RESULT_OPERATION_FAILED
} CBS_OPERATION_RESULT;
typedef struct CBS_INSTANCE_TAG* CBS_HANDLE;
typedef void(*ON_CBS_OPERATION_COMPLETE)(void* context, CBS_OPERATION_RESULT cbs_operation_result, unsigned int status_code, const char* status_description);
extern CBS_HANDLE cbs_create(SESSION_HANDLE session, ON_AMQP_MANAGEMENT_STATE_CHANGED on_amqp_management_state_changed, void* callback_context);
extern void cbs_destroy(CBS_HANDLE cbs);
extern int cbs_open(CBS_HANDLE amqp_management);
extern int cbs_close(CBS_HANDLE amqp_management);
extern int cbs_put_token(CBS_HANDLE cbs, const char* type, const char* audience, const char* token, ON_CBS_OPERATION_COMPLETE on_cbs_operation_complete, void* context);
extern int cbs_delete_token(CBS_HANDLE cbs, const char* type, const char* audience, ON_CBS_OPERATION_COMPLETE on_cbs_operation_complete, void* context);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CBS_H */

91
inc/connection.h Normal file
Просмотреть файл

@ -0,0 +1,91 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef CONNECTION_H
#define CONNECTION_H
#include <stddef.h>
#include <stdint.h>
#include "amqp_frame_codec.h"
#include "amqp_definitions.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct CONNECTION_INSTANCE_TAG* CONNECTION_HANDLE;
typedef struct ENDPOINT_INSTANCE_TAG* ENDPOINT_HANDLE;
typedef enum CONNECTION_STATE_TAG
{
/* Codes_SRS_CONNECTION_01_039: [START In this state a connection exists, but nothing has been sent or received. This is the state an implementation would be in immediately after performing a socket connect or socket accept.] */
CONNECTION_STATE_START,
/* Codes_SRS_CONNECTION_01_040: [HDR RCVD In this state the connection header has been received from the peer but a connection header has not been sent.] */
CONNECTION_STATE_HDR_RCVD,
/* Codes_SRS_CONNECTION_01_041: [HDR SENT In this state the connection header has been sent to the peer but no connection header has been received.] */
CONNECTION_STATE_HDR_SENT,
/* Codes_SRS_CONNECTION_01_042: [HDR EXCH In this state the connection header has been sent to the peer and a connection header has been received from the peer.] */
CONNECTION_STATE_HDR_EXCH,
/* Codes_SRS_CONNECTION_01_043: [OPEN PIPE In this state both the connection header and the open frame have been sent but nothing has been received.] */
CONNECTION_STATE_OPEN_PIPE,
/* Codes_SRS_CONNECTION_01_044: [OC PIPE In this state, the connection header, the open frame, any pipelined connection traffic, and the close frame have been sent but nothing has been received.] */
CONNECTION_STATE_OC_PIPE,
/* Codes_SRS_CONNECTION_01_045: [OPEN RCVD In this state the connection headers have been exchanged. An open frame has been received from the peer but an open frame has not been sent.] */
CONNECTION_STATE_OPEN_RCVD,
/* Codes_SRS_CONNECTION_01_046: [OPEN SENT In this state the connection headers have been exchanged. An open frame has been sent to the peer but no open frame has yet been received.] */
CONNECTION_STATE_OPEN_SENT,
/* Codes_SRS_CONNECTION_01_047: [CLOSE PIPE In this state the connection headers have been exchanged. An open frame, any pipelined connection traffic, and the close frame have been sent but no open frame has yet been received from the peer.] */
CONNECTION_STATE_CLOSE_PIPE,
/* Codes_SRS_CONNECTION_01_048: [OPENED In this state the connection header and the open frame have been both sent and received.] */
CONNECTION_STATE_OPENED,
/* Codes_SRS_CONNECTION_01_049: [CLOSE RCVD In this state a close frame has been received indicating that the peer has initiated an AMQP close.] */
CONNECTION_STATE_CLOSE_RCVD,
/* Codes_SRS_CONNECTION_01_053: [CLOSE SENT In this state a close frame has been sent to the peer. It is illegal to write anything more onto the connection, however there could potentially still be incoming frames.] */
CONNECTION_STATE_CLOSE_SENT,
/* Codes_SRS_CONNECTION_01_055: [DISCARDING The DISCARDING state is a variant of the CLOSE SENT state where the close is triggered by an error.] */
CONNECTION_STATE_DISCARDING,
/* Codes_SRS_CONNECTION_01_057: [END In this state it is illegal for either endpoint to write anything more onto the connection. The connection can be safely closed and discarded.] */
CONNECTION_STATE_END
} CONNECTION_STATE;
typedef void(*ON_ENDPOINT_FRAME_RECEIVED)(void* context, AMQP_VALUE performative, uint32_t frame_payload_size, const unsigned char* payload_bytes);
typedef void(*ON_CONNECTION_STATE_CHANGED)(void* context, CONNECTION_STATE new_connection_state, CONNECTION_STATE previous_connection_state);
typedef bool(*ON_NEW_ENDPOINT)(void* context, ENDPOINT_HANDLE new_endpoint);
extern CONNECTION_HANDLE connection_create(XIO_HANDLE io, const char* hostname, const char* container_id, ON_NEW_ENDPOINT on_new_endpoint, void* callback_context);
extern void connection_destroy(CONNECTION_HANDLE connection);
extern int connection_open(CONNECTION_HANDLE connection);
extern int connection_listen(CONNECTION_HANDLE connection);
extern int connection_close(CONNECTION_HANDLE connection, const char* condition_value, const char* description);
extern int connection_set_max_frame_size(CONNECTION_HANDLE connection, uint32_t max_frame_size);
extern int connection_get_max_frame_size(CONNECTION_HANDLE connection, uint32_t* max_frame_size);
extern int connection_set_channel_max(CONNECTION_HANDLE connection, uint16_t channel_max);
extern int connection_get_channel_max(CONNECTION_HANDLE connection, uint16_t* channel_max);
extern int connection_set_idle_timeout(CONNECTION_HANDLE connection, milliseconds idle_timeout);
extern int connection_get_idle_timeout(CONNECTION_HANDLE connection, milliseconds* idle_timeout);
extern int connection_get_remote_max_frame_size(CONNECTION_HANDLE connection, uint32_t* remote_max_frame_size);
extern void connection_dowork(CONNECTION_HANDLE connection);
extern ENDPOINT_HANDLE connection_create_endpoint(CONNECTION_HANDLE connection);
extern int connection_start_endpoint(ENDPOINT_HANDLE endpoint, ON_ENDPOINT_FRAME_RECEIVED on_frame_received, ON_CONNECTION_STATE_CHANGED on_connection_state_changed, void* context);
extern int connection_endpoint_get_incoming_channel(ENDPOINT_HANDLE endpoint, uint16_t* incoming_channel);
extern void connection_destroy_endpoint(ENDPOINT_HANDLE endpoint);
extern int connection_encode_frame(ENDPOINT_HANDLE endpoint, const AMQP_VALUE performative, PAYLOAD* payloads, size_t payload_count, ON_SEND_COMPLETE on_send_complete, void* callback_context);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CONNECTION_H */

19
inc/consolelogger.h Normal file
Просмотреть файл

@ -0,0 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef CONSOLELOGGER_H
#define CONSOLELOGGER_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include "logger.h"
extern void consolelogger_log(unsigned int options, char* format, ...);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CONSOLELOGGER_H */

57
inc/frame_codec.h Normal file
Просмотреть файл

@ -0,0 +1,57 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef FRAME_CODEC_H
#define FRAME_CODEC_H
#include "xio.h"
#include "logger.h"
#include "amqpvalue.h"
#ifdef __cplusplus
extern "C" {
#include <cstdint>
#include <cstddef>
#include <cstdbool>
#else
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#endif /* __cplusplus */
typedef struct PAYLOAD_TAG
{
const unsigned char* bytes;
uint32_t length;
} PAYLOAD;
/* Codes_SRS_FRAME_CODEC_01_016: [The type code indicates the format and purpose of the frame.] */
/* Codes_SRS_FRAME_CODEC_01_017: [The subsequent bytes in the frame header MAY be interpreted differently depending on the type of the frame.] */
/* Codes_SRS_FRAME_CODEC_01_070: [The type code indicates the format and purpose of the frame.] */
/* Codes_SRS_FRAME_CODEC_01_071: [The subsequent bytes in the frame header MAY be interpreted differently depending on the type of the frame.] */
/* Codes_SRS_FRAME_CODEC_01_018: [A type code of 0x00 indicates that the frame is an AMQP frame.] */
/* Codes_SRS_FRAME_CODEC_01_072: [A type code of 0x00 indicates that the frame is an AMQP frame.] */
#define FRAME_TYPE_AMQP (uint8_t)0x00
/* Codes_SRS_FRAME_CODEC_01_073: [A type code of 0x01 indicates that the frame is a SASL frame] */
/* Codes_SRS_FRAME_CODEC_01_019: [A type code of 0x01 indicates that the frame is a SASL frame] */
#define FRAME_TYPE_SASL (uint8_t)0x01
typedef struct FRAME_CODEC_INSTANCE_TAG* FRAME_CODEC_HANDLE;
typedef void(*ON_FRAME_RECEIVED)(void* context, const unsigned char* type_specific, uint32_t type_specific_size, const unsigned char* frame_body, uint32_t frame_body_size);
typedef void(*ON_FRAME_CODEC_ERROR)(void* context);
typedef void(*ON_BYTES_ENCODED)(void* context, const unsigned char* bytes, size_t length, bool encode_complete);
extern FRAME_CODEC_HANDLE frame_codec_create(ON_FRAME_CODEC_ERROR on_frame_codec_error, void* callback_context, LOGGER_LOG logger_log);
extern void frame_codec_destroy(FRAME_CODEC_HANDLE frame_codec);
extern int frame_codec_set_max_frame_size(FRAME_CODEC_HANDLE frame_codec, uint32_t max_frame_size);
extern int frame_codec_subscribe(FRAME_CODEC_HANDLE frame_codec, uint8_t type, ON_FRAME_RECEIVED on_frame_received, void* callback_context);
extern int frame_codec_unsubscribe(FRAME_CODEC_HANDLE frame_codec, uint8_t type);
extern int frame_codec_receive_bytes(FRAME_CODEC_HANDLE frame_codec, const unsigned char* buffer, size_t size);
extern int frame_codec_encode_frame(FRAME_CODEC_HANDLE frame_codec, uint8_t type, const PAYLOAD* payloads, size_t payload_count, const unsigned char* type_specific_bytes, uint32_t type_specific_size, ON_BYTES_ENCODED encoded_bytes, void* callback_context);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* FRAME_CODEC_H */

30
inc/header_detect_io.h Normal file
Просмотреть файл

@ -0,0 +1,30 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef HEADER_DETECT_IO_H
#define HEADER_DETECT_IO_H
#include "xio.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct HEADERDETECTIO_CONFIG_TAG
{
XIO_HANDLE underlying_io;
} HEADERDETECTIO_CONFIG;
extern CONCRETE_IO_HANDLE headerdetectio_create(void* io_create_parameters, LOGGER_LOG logger_log);
extern void headerdetectio_destroy(CONCRETE_IO_HANDLE header_detect_io);
extern int headerdetectio_open(CONCRETE_IO_HANDLE header_detect_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context);
extern int headerdetectio_close(CONCRETE_IO_HANDLE header_detect_io);
extern int headerdetectio_send(CONCRETE_IO_HANDLE header_detect_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context);
extern void headerdetectio_dowork(CONCRETE_IO_HANDLE header_detect_io);
extern const IO_INTERFACE_DESCRIPTION* headerdetectio_get_interface_description(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* HEADER_DETECT_IO_H */

56
inc/link.h Normal file
Просмотреть файл

@ -0,0 +1,56 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef LINK_H
#define LINK_H
#include <stddef.h>
#include "session.h"
#include "amqpvalue.h"
#include "amqp_definitions.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct LINK_INSTANCE_TAG* LINK_HANDLE;
typedef enum LINK_STATE_TAG
{
LINK_STATE_DETACHED,
LINK_STATE_HALF_ATTACHED,
LINK_STATE_ATTACHED
} LINK_STATE;
typedef enum LINK_TRANSFER_RESULT_TAG
{
LINK_TRANSFER_OK,
LINK_TRANSFER_ERROR,
LINK_TRANSFER_BUSY
} LINK_TRANSFER_RESULT;
typedef void(*ON_DELIVERY_SETTLED)(void* context, delivery_number delivery_no);
typedef AMQP_VALUE(*ON_TRANSFER_RECEIVED)(void* context, TRANSFER_HANDLE transfer, uint32_t payload_size, const unsigned char* payload_bytes);
typedef void(*ON_LINK_STATE_CHANGED)(void* context, LINK_STATE new_link_state, LINK_STATE previous_link_state);
typedef void(*ON_LINK_FLOW_ON)(void* context);
extern LINK_HANDLE link_create(SESSION_HANDLE session, const char* name, role role, AMQP_VALUE source, AMQP_VALUE target);
extern LINK_HANDLE link_create_from_endpoint(SESSION_HANDLE session, LINK_ENDPOINT_HANDLE link_endpoint, const char* name, role role, AMQP_VALUE source, AMQP_VALUE target);
extern void link_destroy(LINK_HANDLE handle);
extern int link_set_snd_settle_mode(LINK_HANDLE link, sender_settle_mode snd_settle_mode);
extern int link_get_snd_settle_mode(LINK_HANDLE link, sender_settle_mode* snd_settle_mode);
extern int link_set_rcv_settle_mode(LINK_HANDLE link, receiver_settle_mode rcv_settle_mode);
extern int link_get_rcv_settle_mode(LINK_HANDLE link, receiver_settle_mode* rcv_settle_mode);
extern int link_set_initial_delivery_count(LINK_HANDLE link, sequence_no initial_delivery_count);
extern int link_get_initial_delivery_count(LINK_HANDLE link, sequence_no* initial_delivery_count);
extern int link_set_max_message_size(LINK_HANDLE link, uint64_t max_message_size);
extern int link_get_max_message_size(LINK_HANDLE link, uint64_t* max_message_size);
extern int link_attach(LINK_HANDLE link, ON_TRANSFER_RECEIVED on_transfer_received, ON_LINK_STATE_CHANGED on_link_state_changed, ON_LINK_FLOW_ON on_link_flow_on, void* callback_context);
extern int link_detach(LINK_HANDLE link);
extern LINK_TRANSFER_RESULT link_transfer(LINK_HANDLE handle, PAYLOAD* payloads, size_t payload_count, ON_DELIVERY_SETTLED on_delivery_settled, void* callback_context);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LINK_H */

22
inc/logger.h Normal file
Просмотреть файл

@ -0,0 +1,22 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef LOGGER_H
#define LOGGER_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef void(*LOGGER_LOG)(unsigned int options, char* format, ...);
#define LOG_LINE 0x01
#define LOG(logger, ...) if (logger != NULL) logger(__VA_ARGS__)
//#define LOG(logger, ...)
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LOGGER_H */

61
inc/message.h Normal file
Просмотреть файл

@ -0,0 +1,61 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef MESSAGE_H
#define MESSAGE_H
#include "amqpvalue.h"
#include "amqp_definitions.h"
#ifdef __cplusplus
extern "C" {
#include <cstddef>
#else
#include <stddef.h>
#endif /* __cplusplus */
typedef enum MESSAGE_BODY_TYPE_TAG
{
MESSAGE_BODY_TYPE_NONE,
MESSAGE_BODY_TYPE_DATA,
MESSAGE_BODY_TYPE_SEQUENCE,
MESSAGE_BODY_TYPE_VALUE
} MESSAGE_BODY_TYPE;
typedef struct MESSAGE_INSTANCE_TAG* MESSAGE_HANDLE;
typedef struct BINARY_DATA_TAG
{
const unsigned char* bytes;
size_t length;
} BINARY_DATA;
extern MESSAGE_HANDLE message_create(void);
extern MESSAGE_HANDLE message_clone(MESSAGE_HANDLE source_message);
extern void message_destroy(MESSAGE_HANDLE message);
extern int message_set_header(MESSAGE_HANDLE message, HEADER_HANDLE message_header);
extern int message_get_header(MESSAGE_HANDLE message, HEADER_HANDLE* message_header);
extern int message_set_delivery_annotations(MESSAGE_HANDLE message, annotations delivery_annotations);
extern int message_get_delivery_annotations(MESSAGE_HANDLE message, annotations* delivery_annotations);
extern int message_set_message_annotations(MESSAGE_HANDLE message, annotations delivery_annotations);
extern int message_get_message_annotations(MESSAGE_HANDLE message, annotations* delivery_annotations);
extern int message_set_properties(MESSAGE_HANDLE message, PROPERTIES_HANDLE properties);
extern int message_get_properties(MESSAGE_HANDLE message, PROPERTIES_HANDLE* properties);
extern int message_set_application_properties(MESSAGE_HANDLE message, AMQP_VALUE application_properties);
extern int message_get_application_properties(MESSAGE_HANDLE message, AMQP_VALUE* application_properties);
extern int message_set_footer(MESSAGE_HANDLE message, annotations footer);
extern int message_get_footer(MESSAGE_HANDLE message, annotations* footer);
extern int message_add_body_amqp_data(MESSAGE_HANDLE message, BINARY_DATA binary_data);
extern int message_get_body_amqp_data(MESSAGE_HANDLE message, size_t index, BINARY_DATA* binary_data);
extern int message_get_body_amqp_data_count(MESSAGE_HANDLE message, size_t* count);
extern int message_set_body_amqp_value(MESSAGE_HANDLE message, AMQP_VALUE body_amqp_value);
extern int message_get_inplace_body_amqp_value(MESSAGE_HANDLE message, AMQP_VALUE* body_amqp_value);
extern int message_get_body_type(MESSAGE_HANDLE message, MESSAGE_BODY_TYPE* body_type);
extern int message_add_body_amqp_sequence(MESSAGE_HANDLE message, AMQP_VALUE sequence_list);
extern int message_get_body_amqp_sequence(MESSAGE_HANDLE message, size_t index, AMQP_VALUE* sequence_list);
extern int message_get_body_amqp_sequence_count(MESSAGE_HANDLE message, size_t* count);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* MESSAGE_H */

37
inc/message_receiver.h Normal file
Просмотреть файл

@ -0,0 +1,37 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef MESSAGE_RECEIVER_H
#define MESSAGE_RECEIVER_H
#include "link.h"
#include "message.h"
#include "amqp_definitions.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef enum MESSAGE_RECEIVER_STATE_TAG
{
MESSAGE_RECEIVER_STATE_IDLE,
MESSAGE_RECEIVER_STATE_OPENING,
MESSAGE_RECEIVER_STATE_OPEN,
MESSAGE_RECEIVER_STATE_CLOSING,
MESSAGE_RECEIVER_STATE_ERROR
} MESSAGE_RECEIVER_STATE;
typedef struct MESSAGE_RECEIVER_INSTANCE_TAG* MESSAGE_RECEIVER_HANDLE;
typedef AMQP_VALUE (*ON_MESSAGE_RECEIVED)(const void* context, MESSAGE_HANDLE message);
typedef void(*ON_MESSAGE_RECEIVER_STATE_CHANGED)(const void* context, MESSAGE_RECEIVER_STATE new_state, MESSAGE_RECEIVER_STATE previous_state);
extern MESSAGE_RECEIVER_HANDLE messagereceiver_create(LINK_HANDLE link, ON_MESSAGE_RECEIVER_STATE_CHANGED on_message_receiver_state_changed, void* context);
extern void messagereceiver_destroy(MESSAGE_RECEIVER_HANDLE message_receiver);
extern int messagereceiver_open(MESSAGE_RECEIVER_HANDLE message_receiver, ON_MESSAGE_RECEIVED on_message_received, const void* callback_context);
extern int messagereceiver_close(MESSAGE_RECEIVER_HANDLE message_receiver);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* MESSAGE_RECEIVER_H */

44
inc/message_sender.h Normal file
Просмотреть файл

@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef MESSAGE_SENDER_H
#define MESSAGE_SENDER_H
#include "link.h"
#include "message.h"
#include "logger.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef enum MESSAGE_SEND_RESULT_TAG
{
MESSAGE_SEND_OK,
MESSAGE_SEND_ERROR
} MESSAGE_SEND_RESULT;
typedef enum MESSAGE_SENDER_STATE_TAG
{
MESSAGE_SENDER_STATE_IDLE,
MESSAGE_SENDER_STATE_OPENING,
MESSAGE_SENDER_STATE_OPEN,
MESSAGE_SENDER_STATE_CLOSING,
MESSAGE_SENDER_STATE_ERROR
} MESSAGE_SENDER_STATE;
typedef struct MESSAGE_SENDER_INSTANCE_TAG* MESSAGE_SENDER_HANDLE;
typedef void(*ON_MESSAGE_SEND_COMPLETE)(const void* context, MESSAGE_SEND_RESULT send_result);
typedef void(*ON_MESSAGE_SENDER_STATE_CHANGED)(const void* context, MESSAGE_SENDER_STATE new_state, MESSAGE_SENDER_STATE previous_state);
extern MESSAGE_SENDER_HANDLE messagesender_create(LINK_HANDLE link, ON_MESSAGE_SENDER_STATE_CHANGED on_message_sender_state_changed, void* context, LOGGER_LOG logger_log);
extern void messagesender_destroy(MESSAGE_SENDER_HANDLE message_sender);
extern int messagesender_open(MESSAGE_SENDER_HANDLE message_sender);
extern int messagesender_close(MESSAGE_SENDER_HANDLE message_sender);
extern int messagesender_send(MESSAGE_SENDER_HANDLE message_sender, MESSAGE_HANDLE message, ON_MESSAGE_SEND_COMPLETE on_message_send_complete, const void* callback_context);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* MESSAGE_SENDER_H */

30
inc/messaging.h Normal file
Просмотреть файл

@ -0,0 +1,30 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef MESSAGING_H
#define MESSAGING_H
#include "amqpvalue.h"
#include "amqp_definitions.h"
#ifdef __cplusplus
#include <cstdint>
extern "C" {
#else
#include <stdint.h>
#endif /* __cplusplus */
extern AMQP_VALUE messaging_create_source(const char* address);
extern AMQP_VALUE messaging_create_target(const char* address);
extern AMQP_VALUE messaging_delivery_received(uint32_t section_number, uint64_t section_offset);
extern AMQP_VALUE messaging_delivery_accepted(void);
extern AMQP_VALUE messaging_delivery_rejected(const char* error_condition, const char* error_description);
extern AMQP_VALUE messaging_delivery_released(void);
extern AMQP_VALUE messaging_delivery_modified(bool delivery_failed, bool undeliverable_here, fields message_annotations);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* MESSAGING_H */

24
inc/sasl_anonymous.h Normal file
Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SASL_ANONYMOUS_H
#define SASL_ANONYMOUS_H
#include "sasl_mechanism.h"
#include "logger.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern CONCRETE_SASL_MECHANISM_HANDLE saslanonymous_create(void* config);
extern void saslanonymous_destroy(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
extern int saslanonymous_get_init_bytes(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism, SASL_MECHANISM_BYTES* init_bytes);
extern const char* saslanonymous_get_mechanism_name(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
extern const SASL_MECHANISM_INTERFACE_DESCRIPTION* saslanonymous_get_interface(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SASL_ANONYMOUS_H */

35
inc/sasl_frame_codec.h Normal file
Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SASL_FRAME_CODEC_H
#define SASL_FRAME_CODEC_H
#ifdef __cplusplus
extern "C" {
#include <cstdint>
#include <cstddef>
#else
#include <stdint.h>
#include <stddef.h>
#endif /* __cplusplus */
#include "frame_codec.h"
#define SASL_MECHANISMS (uint64_t)0x40
#define SASL_INIT (uint64_t)0x41
#define SASL_CHALLENGE (uint64_t)0x42
#define SASL_RESPONSE (uint64_t)0x43
#define SASL_OUTCOME (uint64_t)0x44
typedef struct SASL_FRAME_CODEC_INSTANCE_TAG* SASL_FRAME_CODEC_HANDLE;
typedef void(*ON_SASL_FRAME_RECEIVED)(void* context, AMQP_VALUE sasl_frame_value);
typedef void(*ON_SASL_FRAME_CODEC_ERROR)(void* context);
extern SASL_FRAME_CODEC_HANDLE sasl_frame_codec_create(FRAME_CODEC_HANDLE frame_codec, ON_SASL_FRAME_RECEIVED on_sasl_frame_received, ON_SASL_FRAME_CODEC_ERROR on_sasl_frame_codec_error, void* callback_context);
extern void sasl_frame_codec_destroy(SASL_FRAME_CODEC_HANDLE sasl_frame_codec);
extern int sasl_frame_codec_encode_frame(SASL_FRAME_CODEC_HANDLE sasl_frame_codec, const AMQP_VALUE sasl_frame_value, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SASL_FRAME_CODEC_H */

46
inc/sasl_mechanism.h Normal file
Просмотреть файл

@ -0,0 +1,46 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SASL_MECHANISM_H
#define SASL_MECHANISM_H
#include "link.h"
#include "message.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct SASL_MECHANISM_INSTANCE_TAG* SASL_MECHANISM_HANDLE;
typedef void* CONCRETE_SASL_MECHANISM_HANDLE;
typedef struct INIT_BYTES_TAG
{
const void* bytes;
size_t length;
} SASL_MECHANISM_BYTES;
typedef CONCRETE_SASL_MECHANISM_HANDLE(*SASL_MECHANISM_CREATE)(void* config);
typedef void(*SASL_MECHANISM_DESTROY)(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
typedef int(*SASL_MECHANISM_GET_INIT_BYTES)(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism, SASL_MECHANISM_BYTES* init_bytes);
typedef const char*(*SASL_MECHANISM_GET_MECHANISM_NAME)(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism);
typedef struct SASL_MECHANISM_INTERFACE_TAG
{
SASL_MECHANISM_CREATE concrete_sasl_mechanism_create;
SASL_MECHANISM_DESTROY concrete_sasl_mechanism_destroy;
SASL_MECHANISM_GET_INIT_BYTES concrete_sasl_mechanism_get_init_bytes;
SASL_MECHANISM_GET_MECHANISM_NAME concrete_sasl_mechanism_get_mechanism_name;
} SASL_MECHANISM_INTERFACE_DESCRIPTION;
extern SASL_MECHANISM_HANDLE saslmechanism_create(const SASL_MECHANISM_INTERFACE_DESCRIPTION* sasl_mechanism_interface_description, void* sasl_mechanism_create_parameters);
extern void saslmechanism_destroy(SASL_MECHANISM_HANDLE sasl_mechanism);
extern int saslmechanism_get_init_bytes(SASL_MECHANISM_HANDLE sasl_mechanism, SASL_MECHANISM_BYTES* init_bytes);
extern const char* saslmechanism_get_mechanism_name(SASL_MECHANISM_HANDLE sasl_mechanism);
extern int saslmechanism_challenge(SASL_MECHANISM_HANDLE sasl_mechanism, const SASL_MECHANISM_BYTES* challenge_bytes, SASL_MECHANISM_BYTES* response_bytes);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SASL_MECHANISM_H */

23
inc/sasl_mssbcbs.h Normal file
Просмотреть файл

@ -0,0 +1,23 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SASL_MSSBCBS_H
#define SASL_MSSBCBS_H
#include "sasl_mechanism.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern CONCRETE_SASL_MECHANISM_HANDLE saslmssbcbs_create(void* config);
extern void saslmssbcbs_destroy(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle);
extern int saslmssbcbs_get_init_bytes(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle, SASL_MECHANISM_BYTES* init_bytes);
extern const char* saslmssbcbs_get_mechanism_name(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism);
extern const SASL_MECHANISM_INTERFACE_DESCRIPTION* saslmssbcbs_get_interface(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SASL_MSSBCBS_H */

29
inc/sasl_plain.h Normal file
Просмотреть файл

@ -0,0 +1,29 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SASL_PLAIN_H
#define SASL_PLAIN_H
#include "sasl_mechanism.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct SASL_PLAIN_CONFIG_TAG
{
const char* authcid;
const char* passwd;
} SASL_PLAIN_CONFIG;
extern CONCRETE_SASL_MECHANISM_HANDLE saslplain_create(void* config);
extern void saslplain_destroy(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle);
extern int saslplain_get_init_bytes(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle, SASL_MECHANISM_BYTES* init_bytes);
extern const char* saslplain_get_mechanism_name(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism);
extern const SASL_MECHANISM_INTERFACE_DESCRIPTION* saslplain_get_interface(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SASL_PLAIN_H */

36
inc/saslclientio.h Normal file
Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SASLCLIENTIO_H
#define SASLCLIENTIO_H
#ifdef __cplusplus
extern "C" {
#include <cstddef>
#else
#include <stddef.h>
#endif /* __cplusplus */
#include "xio.h"
#include "sasl_mechanism.h"
#include "logger.h"
typedef struct SASLCLIENTIO_CONFIG_TAG
{
XIO_HANDLE underlying_io;
SASL_MECHANISM_HANDLE sasl_mechanism;
} SASLCLIENTIO_CONFIG;
extern CONCRETE_IO_HANDLE saslclientio_create(void* io_create_parameters, LOGGER_LOG logger_log);
extern void saslclientio_destroy(CONCRETE_IO_HANDLE sasl_client_io);
extern int saslclientio_open(CONCRETE_IO_HANDLE sasl_client_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context);
extern int saslclientio_close(CONCRETE_IO_HANDLE sasl_client_io);
extern int saslclientio_send(CONCRETE_IO_HANDLE sasl_client_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context);
extern void saslclientio_dowork(CONCRETE_IO_HANDLE sasl_client_io);
extern const IO_INTERFACE_DESCRIPTION* saslclientio_get_interface_description(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SASLCLIENTIO_H */

66
inc/session.h Normal file
Просмотреть файл

@ -0,0 +1,66 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SESSION_H
#define SESSION_H
#include <stdint.h>
#include "amqpvalue.h"
#include "amqp_frame_codec.h"
#include "connection.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct SESSION_INSTANCE_TAG* SESSION_HANDLE;
typedef struct LINK_ENDPOINT_INSTANCE_TAG* LINK_ENDPOINT_HANDLE;
typedef enum SESION_STATE_TAG
{
SESSION_STATE_UNMAPPED,
SESSION_STATE_BEGIN_SENT,
SESSION_STATE_BEGIN_RCVD,
SESSION_STATE_MAPPED,
SESSION_STATE_END_SENT,
SESSION_STATE_END_RCVD,
SESSION_STATE_DISCARDING
} SESSION_STATE;
typedef enum SESSION_SEND_TRANSFER_RESULT_TAG
{
SESSION_SEND_TRANSFER_OK,
SESSION_SEND_TRANSFER_ERROR,
SESSION_SEND_TRANSFER_BUSY
} SESSION_SEND_TRANSFER_RESULT;
typedef void(*LINK_ENDPOINT_FRAME_RECEIVED_CALLBACK)(void* context, AMQP_VALUE performative, uint32_t frame_payload_size, const unsigned char* payload_bytes);
typedef void(*ON_SESSION_STATE_CHANGED)(void* context, SESSION_STATE new_session_state, SESSION_STATE previous_session_state);
typedef void(*ON_SESSION_FLOW_ON)(void* context);
typedef bool(*ON_LINK_ATTACHED)(void* context, LINK_ENDPOINT_HANDLE new_link_endpoint, const char* name, role role, AMQP_VALUE source, AMQP_VALUE target);
extern SESSION_HANDLE session_create(CONNECTION_HANDLE connection, ON_LINK_ATTACHED on_link_attached, void* callback_context);
extern SESSION_HANDLE session_create_from_endpoint(CONNECTION_HANDLE connection, ENDPOINT_HANDLE connection_endpoint, ON_LINK_ATTACHED on_link_attached, void* callback_context);
extern int session_set_incoming_window(SESSION_HANDLE session, uint32_t incoming_window);
extern int session_get_incoming_window(SESSION_HANDLE session, uint32_t* incoming_window);
extern int session_set_outgoing_window(SESSION_HANDLE session, uint32_t outgoing_window);
extern int session_get_outgoing_window(SESSION_HANDLE session, uint32_t* outgoing_window);
extern int session_set_handle_max(SESSION_HANDLE session, handle handle_max);
extern int session_get_handle_max(SESSION_HANDLE session, handle* handle_max);
extern void session_destroy(SESSION_HANDLE session);
extern int session_begin(SESSION_HANDLE session);
extern int session_end(SESSION_HANDLE session, const char* condition_value, const char* description);
extern LINK_ENDPOINT_HANDLE session_create_link_endpoint(SESSION_HANDLE session, const char* name);
extern void session_destroy_link_endpoint(LINK_ENDPOINT_HANDLE link_endpoint);
extern int session_start_link_endpoint(LINK_ENDPOINT_HANDLE link_endpoint, ON_ENDPOINT_FRAME_RECEIVED frame_received_callback, ON_SESSION_STATE_CHANGED on_session_state_changed, ON_SESSION_FLOW_ON on_session_flow_on, void* context);
extern int session_send_flow(LINK_ENDPOINT_HANDLE link_endpoint, FLOW_HANDLE flow);
extern int session_send_attach(LINK_ENDPOINT_HANDLE link_endpoint, ATTACH_HANDLE attach);
extern int session_send_disposition(LINK_ENDPOINT_HANDLE link_endpoint, DISPOSITION_HANDLE disposition);
extern int session_send_detach(LINK_ENDPOINT_HANDLE link_endpoint, DETACH_HANDLE detach);
extern SESSION_SEND_TRANSFER_RESULT session_send_transfer(LINK_ENDPOINT_HANDLE link_endpoint, TRANSFER_HANDLE transfer, PAYLOAD* payloads, size_t payload_count, delivery_number* delivery_id, ON_SEND_COMPLETE on_send_complete, void* callback_context);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SESSION_H */

26
inc/socket_listener.h Normal file
Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SOCKETLISTENER_H
#define SOCKETLISTENER_H
#include "xio.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct SOCKET_LISTENER_INSTANCE_TAG* SOCKET_LISTENER_HANDLE;
typedef void(*ON_SOCKET_ACCEPTED)(void* context, XIO_HANDLE socket_io);
extern SOCKET_LISTENER_HANDLE socketlistener_create(int port);
extern void socketlistener_destroy(SOCKET_LISTENER_HANDLE socket_listener);
extern int socketlistener_start(SOCKET_LISTENER_HANDLE socket_listener, ON_SOCKET_ACCEPTED on_socket_accepted, void* callback_context);
extern int socketlistener_stop(SOCKET_LISTENER_HANDLE socket_listener);
extern void socketlistener_dowork(SOCKET_LISTENER_HANDLE socket_listener);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SOCKETLISTENER_H */

42
inc/wsio.h Normal file
Просмотреть файл

@ -0,0 +1,42 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef WSIO_H
#define WSIO_H
#ifdef __cplusplus
extern "C" {
#include <cstddef>
#include <cstdbool>
#else
#include <stddef.h>
#include <stdbool.h>
#endif /* __cplusplus */
#include "xio.h"
#include "sasl_mechanism.h"
#include "logger.h"
typedef struct WSIO_CONFIG_TAG
{
const char* host;
int port;
const char* protocol_name;
const char* relative_path;
bool use_ssl;
const char* trusted_ca;
} WSIO_CONFIG;
extern CONCRETE_IO_HANDLE wsio_create(void* io_create_parameters, LOGGER_LOG logger_log);
extern void wsio_destroy(CONCRETE_IO_HANDLE ws_io);
extern int wsio_open(CONCRETE_IO_HANDLE ws_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context);
extern int wsio_close(CONCRETE_IO_HANDLE ws_io);
extern int wsio_send(CONCRETE_IO_HANDLE ws_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context);
extern void wsio_dowork(CONCRETE_IO_HANDLE ws_io);
extern const IO_INTERFACE_DESCRIPTION* wsio_get_interface_description(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* WSIO_H */

Просмотреть файл

@ -0,0 +1,89 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include "mbed.h"
#include <stddef.h>
#include "TCPSocketConnection.h"
#include "tcpsocketconnection_c.h"
extern "C"
{
TCPSOCKETCONNECTION_HANDLE connHandle;
}
TCPSOCKETCONNECTION_HANDLE tcpsocketconnection_create(void)
{
return (TCPSOCKETCONNECTION_HANDLE)new TCPSocketConnection();
}
void tcpsocketconnection_set_blocking(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, bool blocking, unsigned int timeout)
{
TCPSocketConnection* tsc = (TCPSocketConnection*)tcpSocketConnectionHandle;
tsc->set_blocking(blocking, timeout);
}
void tcpsocketconnection_destroy(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle)
{
delete (TCPSocketConnection*)tcpSocketConnectionHandle;
}
int tcpsocketconnection_connect(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, const char* host, const int port)
{
TCPSocketConnection* tsc = (TCPSocketConnection*)tcpSocketConnectionHandle;
return tsc->connect(host, port);
}
bool tcpsocketconnection_is_connected(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle)
{
TCPSocketConnection* tsc = (TCPSocketConnection*)tcpSocketConnectionHandle;
return tsc->is_connected();
}
void tcpsocketconnection_close(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle)
{
TCPSocketConnection* tsc = (TCPSocketConnection*)tcpSocketConnectionHandle;
tsc->close();
}
int tcpsocketconnection_send(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, const char* data, int length)
{
TCPSocketConnection* tsc = (TCPSocketConnection*)tcpSocketConnectionHandle;
return tsc->send((char*)data, length);
}
int tcpsocketconnection_send_all(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, const char* data, int length)
{
TCPSocketConnection* tsc = (TCPSocketConnection*)tcpSocketConnectionHandle;
return tsc->send_all((char*)data, length);
}
int tcpsocketconnection_receive(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, char* data, int length)
{
TCPSocketConnection* tsc = (TCPSocketConnection*)tcpSocketConnectionHandle;
return tsc->receive(data, length);
}
int tcpsocketconnection_receive_all(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, char* data, int length)
{
TCPSocketConnection* tsc = (TCPSocketConnection*)tcpSocketConnectionHandle;
return tsc->receive_all(data, length);
}

Просмотреть файл

@ -0,0 +1,25 @@
#ifndef TCPSOCKETCONNECTION_C_H
#define TCPSOCKETCONNECTION_C_H
#ifdef __cplusplus
extern "C" {
#endif
typedef void* TCPSOCKETCONNECTION_HANDLE;
TCPSOCKETCONNECTION_HANDLE tcpsocketconnection_create(void);
void tcpsocketconnection_set_blocking(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, bool blocking, unsigned int timeout);
void tcpsocketconnection_destroy(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle);
int tcpsocketconnection_connect(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, const char* host, const int port);
bool tcpsocketconnection_is_connected(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle);
void tcpsocketconnection_close(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle);
int tcpsocketconnection_send(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, const char* data, int length);
int tcpsocketconnection_send_all(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, const char* data, int length);
int tcpsocketconnection_receive(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, char* data, int length);
int tcpsocketconnection_receive_all(TCPSOCKETCONNECTION_HANDLE tcpSocketConnectionHandle, char* data, int length);
#ifdef __cplusplus
}
#endif
#endif /* TCPSOCKETCONNECTION_C_H */

61
mbed/tickcounter.c Normal file
Просмотреть файл

@ -0,0 +1,61 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdint.h>
#include <time.h>
#include "tickcounter.h"
#include "amqpalloc.h"
typedef struct TICK_COUNTER_INSTANCE_TAG
{
clock_t last_clock_value;
uint64_t current_ms;
} TICK_COUNTER_INSTANCE;
TICK_COUNTER_HANDLE tickcounter_create(void)
{
TICK_COUNTER_INSTANCE* result = (TICK_COUNTER_INSTANCE*)amqpalloc_malloc(sizeof(TICK_COUNTER_INSTANCE));
if (result != NULL)
{
result->last_clock_value = clock();
result->current_ms = result->last_clock_value * 1000 / CLOCKS_PER_SEC;
}
return result;
}
void tickcounter_destroy(TICK_COUNTER_HANDLE tick_counter)
{
if (tick_counter != NULL)
{
amqpalloc_free(tick_counter);
}
}
int tickcounter_get_current_ms(TICK_COUNTER_HANDLE tick_counter, uint64_t* current_ms)
{
int result;
if (tick_counter == NULL)
{
result = __LINE__;
}
else
{
TICK_COUNTER_INSTANCE* tick_counter_instance = (TICK_COUNTER_INSTANCE*)tick_counter;
clock_t clock_value = clock();
tick_counter_instance->current_ms += (clock_value - tick_counter_instance->last_clock_value) * 1000 / CLOCKS_PER_SEC;
tick_counter_instance->last_clock_value = clock_value;
*current_ms = tick_counter_instance->current_ms;
result = 0;
}
return result;
}

27
mbed/tickcounter.h Normal file
Просмотреть файл

@ -0,0 +1,27 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef TICKCOUNTER_H
#define TICKCOUNTER_H
#include "amqpvalue.h"
#include "amqp_definitions.h"
#ifdef __cplusplus
extern "C" {
#include <cstdint>
#else
#include <stdint.h>
#endif /* __cplusplus */
typedef struct TICK_COUNTER_INSTANCE_TAG* TICK_COUNTER_HANDLE;
extern TICK_COUNTER_HANDLE tickcounter_create(void);
extern void tickcounter_destroy(TICK_COUNTER_HANDLE tick_counter);
extern int tickcounter_get_current_ms(TICK_COUNTER_HANDLE tick_counter, uint64_t* current_ms);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* TICKCOUNTER_H */

53
readme.md Normal file
Просмотреть файл

@ -0,0 +1,53 @@
# uAMQP
uAMQP is a general purpose C library for AMQP.
The goal is to be as compliant with the standard as possible while optimizing for low RAM footprint and also being portable.
It is currently a client side implementation only. Although much of the standardis symmetrical, there are parts that are asymmetrical, like the SASL handshake.
Currently uAMQP does not provide the server side for these asymmetrical protions of the ISO.
## Dependencies
uAMQP uses azure-c-shared-utility, which is a C library provising common functionality for basic tasks (like string, list manipulation, IO, etc.).
azure-c-shared-utility is available here: https://github.com/Azure/azure-c-shared-utility.
azure-c-shared-utility needs to be built before building uAMQP.
azure-c-shared-utility provides 3 tlsio implementations:
- tlsio_schannel - runs only on Windows
- tlsio_openssl - depends on OpenSSL being installed
- tlsio_wolfssl - depends on WolfSSL being installed
For more information about configuring azure-c-shared-utility see https://github.com/Azure/azure-c-shared-utility.
uAMQP uses cmake for configuring build files.
For WebSockets support uAMQP depends on libwebsockets, which is available here: https://github.com/warmcat/libwebsockets.
## Setup
1. Clone azure-uamqp-c ie git clone --recursive https://github.com/Azure/azure-uamqp-c.git
2. Create a folder build under azure-uamqp-c
3. Switch to the build folder and run
cmake ..
## Websocket support
In order to use WebSocket support please first clone libwebsockets and build it by creating a build folder under the libwebsockets folder (like c:/libwebsockets/build) and run cmake and build libwebsockets in this build folder.
Once that is done proceed with uAMQP and:
- set the environment variable WSDir to the libwebsockets library location (on Windows something like "set WSDir=c:/libwebsockets").
- run "cmake .. -Dwsio:bool=ON" to enable websocket support.
- build
## Samples
Samples are available in the azure-uamqp-c/samples folder:
- Send messages to an Event Hub
- Receive messages from an Event Hub
- Send messages to an IoT Hub using CBS
- Send messages to an IoT Hub using AMQP over WebSockets

20
samples/CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,20 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
function(add_sample_directory whatIsBuilding)
add_subdirectory(${whatIsBuilding})
set_target_properties(${whatIsBuilding}
PROPERTIES
FOLDER "Samples")
endfunction()
add_sample_directory(message_sender_sample)
add_sample_directory(message_receiver_sample)
add_sample_directory(mssbcbs_sample)
add_sample_directory(local_client_sample)
add_sample_directory(local_server_sample)
if(${wsio})
add_sample_directory(websockets_sample)
endif()

Просмотреть файл

@ -0,0 +1,36 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
compileAsC11()
add_executable(local_client_sample
main.c)
#TODO: link to whatever else the platform has (now for windows it is just ws2_32)
include_directories(.)
if(WIN32)
#windows needs this define
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DGB_MEASURE_MEMORY_FOR_THIS -DGB_DEBUG_ALLOC)
target_link_libraries(local_client_sample
uamqp
aziotsharedutil
ws2_32
secur32)
if(${use_openssl})
target_link_libraries(local_client_sample
$ENV{OpenSSLDir}/lib/ssleay32.lib $ENV{OpenSSLDir}/lib/libeay32.lib)
file(COPY $ENV{OpenSSLDir}/bin/libeay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
file(COPY $ENV{OpenSSLDir}/bin/ssleay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
endif()
else()
target_link_libraries(local_client_sample uamqp aziotsharedutil ssl crypto)
endif()
if(${tlsio_wolfssl})
target_link_libraries(local_client_sample $ENV{WolfSSLDir}/Debug/wolfssl.lib)
endif()

Просмотреть файл

@ -0,0 +1,143 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdio.h>
#include <stdbool.h>
#include "platform.h"
#include "message_sender.h"
#include "message.h"
#include "messaging.h"
#include "amqpalloc.h"
#include "socketio.h"
#include "consolelogger.h"
#if _WIN32
#include "windows.h"
#endif
static const size_t msg_count = 1000;
static unsigned int sent_messages = 0;
static void on_message_send_complete(const void* context, MESSAGE_SEND_RESULT send_result)
{
(void)send_result;
(void)context;
sent_messages++;
//printf("Sent %lu.\r\n", sent_messages);
}
int main(int argc, char** argv)
{
int result;
amqpalloc_set_memory_tracing_enabled(true);
if (platform_init() != 0)
{
result = -1;
}
else
{
CONNECTION_HANDLE connection;
SESSION_HANDLE session;
LINK_HANDLE link;
MESSAGE_SENDER_HANDLE message_sender;
MESSAGE_HANDLE message;
size_t last_memory_used = 0;
/* create socket IO */
XIO_HANDLE socket_io;
SOCKETIO_CONFIG socketio_config = { "localhost", 5672, NULL };
socket_io = xio_create(socketio_get_interface_description(), &socketio_config, NULL);
/* create the connection, session and link */
connection = connection_create(socket_io, "localhost", "some", NULL, NULL);
session = session_create(connection, NULL, NULL);
session_set_incoming_window(session, 2147483647);
session_set_outgoing_window(session, 65536);
AMQP_VALUE source = messaging_create_source("ingress");
AMQP_VALUE target = messaging_create_target("localhost/ingress");
link = link_create(session, "sender-link", role_sender, source, target);
link_set_snd_settle_mode(link, sender_settle_mode_settled);
(void)link_set_max_message_size(link, 65536);
amqpvalue_destroy(source);
amqpvalue_destroy(target);
message = message_create();
unsigned char hello[] = { 'H', 'e', 'l', 'l', 'o' };
BINARY_DATA binary_data = { hello, sizeof(hello) };
message_add_body_amqp_data(message, binary_data);
/* create a message sender */
message_sender = messagesender_create(link, NULL, NULL, NULL);
if (messagesender_open(message_sender) == 0)
{
uint32_t i;
#if _WIN32
unsigned long startTime = (unsigned long)GetTickCount64();
#endif
for (i = 0; i < msg_count; i++)
{
(void)messagesender_send(message_sender, message, on_message_send_complete, message);
}
message_destroy(message);
while (true)
{
size_t current_memory_used;
size_t maximum_memory_used;
connection_dowork(connection);
current_memory_used = amqpalloc_get_current_memory_used();
maximum_memory_used = amqpalloc_get_maximum_memory_used();
if (current_memory_used != last_memory_used)
{
printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used);
last_memory_used = current_memory_used;
}
if (sent_messages == msg_count)
{
break;
}
}
#if _WIN32
unsigned long endTime = (unsigned long)GetTickCount64();
printf("Send %lu messages in %lu ms: %.02f msgs/sec\r\n", msg_count, (endTime - startTime), (float)msg_count / ((float)(endTime - startTime) / 1000));
#endif
}
messagesender_destroy(message_sender);
link_destroy(link);
session_destroy(session);
connection_destroy(connection);
xio_destroy(socket_io);
platform_deinit();
printf("Max memory usage:%lu\r\n", (unsigned long)amqpalloc_get_maximum_memory_used());
printf("Current memory usage:%lu\r\n", (unsigned long)amqpalloc_get_current_memory_used());
result = 0;
}
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();
#endif
return result;
}

Просмотреть файл

@ -0,0 +1,36 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
compileAsC11()
add_executable(local_server_sample
main.c)
#TODO: link to whatever else the platform has (now for windows it is just ws2_32)
include_directories(.)
if (WIN32)
#windows needs this define
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DGB_MEASURE_MEMORY_FOR_THIS -DGB_DEBUG_ALLOC)
target_link_libraries(local_server_sample
uamqp
aziotsharedutil
ws2_32
secur32)
if(${use_openssl})
target_link_libraries(local_server_sample
$ENV{OpenSSLDir}/lib/ssleay32.lib $ENV{OpenSSLDir}/lib/libeay32.lib)
file(COPY $ENV{OpenSSLDir}/bin/libeay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
file(COPY $ENV{OpenSSLDir}/bin/ssleay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
endif()
else()
target_link_libraries(local_server_sample uamqp aziotsharedutil ssl crypto)
endif()
if(${tlsio_wolfssl})
target_link_libraries(local_server_sample $ENV{WolfSSLDir}/Debug/wolfssl.lib)
endif()

Просмотреть файл

@ -0,0 +1,131 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdio.h>
#include <stdbool.h>
#include "platform.h"
#include "message_receiver.h"
#include "message.h"
#include "messaging.h"
#include "amqpalloc.h"
#include "socket_listener.h"
#include "header_detect_io.h"
#include "consolelogger.h"
#include "xio.h"
#include "connection.h"
#include "session.h"
#include "link.h"
static unsigned int sent_messages = 0;
static const size_t msg_count = 1;
static CONNECTION_HANDLE connection;
static SESSION_HANDLE session;
static LINK_HANDLE link;
static MESSAGE_RECEIVER_HANDLE message_receiver;
static void on_message_receiver_state_changed(const void* context, MESSAGE_RECEIVER_STATE new_state, MESSAGE_RECEIVER_STATE previous_state)
{
}
static AMQP_VALUE on_message_received(const void* context, MESSAGE_HANDLE message)
{
(void)message;
(void)context;
printf("Message received.\r\n");
return messaging_delivery_accepted();
}
static bool on_new_link_attached(void* context, LINK_ENDPOINT_HANDLE new_link_endpoint, const char* name, role role, AMQP_VALUE source, AMQP_VALUE target)
{
link = link_create_from_endpoint(session, new_link_endpoint, name, role, source, target);
link_set_rcv_settle_mode(link, receiver_settle_mode_first);
message_receiver = messagereceiver_create(link, on_message_receiver_state_changed, NULL);
messagereceiver_open(message_receiver, on_message_received, NULL);
return true;
}
static bool on_new_session_endpoint(void* context, ENDPOINT_HANDLE new_endpoint)
{
session = session_create_from_endpoint(connection, new_endpoint, on_new_link_attached, NULL);
session_set_incoming_window(session, 10000);
session_begin(session);
return true;
}
static void on_socket_accepted(void* context, XIO_HANDLE io)
{
HEADERDETECTIO_CONFIG header_detect_io_config = { io };
XIO_HANDLE header_detect_io = xio_create(headerdetectio_get_interface_description(), &header_detect_io_config, NULL);
connection = connection_create(header_detect_io, NULL, "1", on_new_session_endpoint, NULL);
connection_listen(connection);
}
int main(int argc, char** argv)
{
int result;
amqpalloc_set_memory_tracing_enabled(true);
if (platform_init() != 0)
{
result = -1;
}
else
{
size_t last_memory_used = 0;
SOCKET_LISTENER_HANDLE socket_listener = socketlistener_create(5672);
if (socketlistener_start(socket_listener, on_socket_accepted, NULL) != 0)
{
result = -1;
}
else
{
while (true)
{
size_t current_memory_used;
size_t maximum_memory_used;
socketlistener_dowork(socket_listener);
current_memory_used = amqpalloc_get_current_memory_used();
maximum_memory_used = amqpalloc_get_maximum_memory_used();
if (current_memory_used != last_memory_used)
{
printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used);
last_memory_used = current_memory_used;
}
if (sent_messages == msg_count)
{
break;
}
if (connection != NULL)
{
connection_dowork(connection);
}
}
result = 0;
}
socketlistener_destroy(socket_listener);
platform_deinit();
printf("Max memory usage:%lu\r\n", (unsigned long)amqpalloc_get_maximum_memory_used());
printf("Current memory usage:%lu\r\n", (unsigned long)amqpalloc_get_current_memory_used());
}
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();
#endif
return result;
}

Просмотреть файл

@ -0,0 +1,37 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
compileAsC11()
add_executable(message_receiver_sample
main.c)
#TODO: link to whatever else the platform has (now for windows it is just ws2_32)
include_directories(.)
if (WIN32)
#windows needs this define
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DGB_MEASURE_MEMORY_FOR_THIS -DGB_DEBUG_ALLOC)
target_link_libraries(message_receiver_sample
uamqp
aziotsharedutil
ws2_32
secur32)
if(${use_openssl})
target_link_libraries(message_receiver_sample
$ENV{OpenSSLDir}/lib/ssleay32.lib $ENV{OpenSSLDir}/lib/libeay32.lib)
file(COPY $ENV{OpenSSLDir}/bin/libeay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
file(COPY $ENV{OpenSSLDir}/bin/ssleay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
endif()
else()
target_link_libraries(message_receiver_sample uamqp aziotsharedutil ssl crypto)
endif()
if(${tlsio_wolfssl})
target_link_libraries(message_receiver_sample $ENV{WolfSSLDir}/Debug/wolfssl.lib)
endif()

Просмотреть файл

@ -0,0 +1,144 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdio.h>
#include <stdbool.h>
#include "platform.h"
#include "message_receiver.h"
#include "message.h"
#include "messaging.h"
#include "amqpalloc.h"
#include "saslclientio.h"
#include "sasl_plain.h"
#if _WIN32
#include "tlsio_schannel.h"
#else
#ifdef MBED_BUILD_TIMESTAMP
#include "tlsio_wolfssl.h"
#else
#include "tlsio_openssl.h"
#endif
#endif
#include "consolelogger.h"
/* This sample connects to an Event Hub, authenticates using SASL PLAIN (key name/key) and then it received all messages for partition 0 */
/* Replace the below settings with your own.*/
#define EH_HOST "<<<Replace with your own EH host (like myeventhub.servicebus.windows.net)>>>"
#define EH_KEY_NAME "<<<Replace with your own key name>>>"
#define EH_KEY "<<<Replace with your own key>>>"
static AMQP_VALUE on_message_received(const void* context, MESSAGE_HANDLE message)
{
(void)message;
(void)context;
printf("Message received.\r\n");
return messaging_delivery_accepted();
}
int main(int argc, char** argv)
{
int result;
XIO_HANDLE sasl_io = NULL;
CONNECTION_HANDLE connection = NULL;
SESSION_HANDLE session = NULL;
LINK_HANDLE link = NULL;
MESSAGE_RECEIVER_HANDLE message_receiver = NULL;
amqpalloc_set_memory_tracing_enabled(true);
if (platform_init() != 0)
{
result = -1;
}
else
{
size_t last_memory_used = 0;
/* create SASL plain handler */
SASL_PLAIN_CONFIG sasl_plain_config = { EH_KEY_NAME, EH_KEY };
SASL_MECHANISM_HANDLE sasl_mechanism_handle = saslmechanism_create(saslplain_get_interface(), &sasl_plain_config);
XIO_HANDLE tls_io;
/* create the TLS IO */
#if _WIN32
TLSIO_SCHANNEL_CONFIG tls_io_config = { EH_HOST, 5671 };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = tlsio_schannel_get_interface_description();
#else
#ifdef MBED_BUILD_TIMESTAMP
TLSIO_WOLFSSL_CONFIG tls_io_config = { EH_HOST, 5671 };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = tlsio_wolfssl_get_interface_description();
#else
TLSIO_OPENSSL_CONFIG tls_io_config = { EH_HOST, 5671 };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = tlsio_openssl_get_interface_description();
#endif
#endif
tls_io = xio_create(tlsio_interface, &tls_io_config, NULL);
/* create the SASL client IO using the TLS IO */
SASLCLIENTIO_CONFIG sasl_io_config = { tls_io, sasl_mechanism_handle };
sasl_io = xio_create(saslclientio_get_interface_description(), &sasl_io_config, NULL);
/* create the connection, session and link */
connection = connection_create(sasl_io, EH_HOST, "whatever", NULL, NULL);
session = session_create(connection, NULL, NULL);
/* set incoming window to 100 for the session */
session_set_incoming_window(session, 100);
AMQP_VALUE source = messaging_create_source("amqps://" EH_HOST "/ingress/ConsumerGroups/$Default/Partitions/0");
AMQP_VALUE target = messaging_create_target("ingress-rx");
link = link_create(session, "receiver-link", role_receiver, source, target);
link_set_rcv_settle_mode(link, receiver_settle_mode_first);
amqpvalue_destroy(source);
amqpvalue_destroy(target);
/* create a message receiver */
message_receiver = messagereceiver_create(link, NULL, NULL);
if ((message_receiver == NULL) ||
(messagereceiver_open(message_receiver, on_message_received, message_receiver) != 0))
{
result = -1;
}
else
{
while (true)
{
size_t current_memory_used;
size_t maximum_memory_used;
connection_dowork(connection);
current_memory_used = amqpalloc_get_current_memory_used();
maximum_memory_used = amqpalloc_get_maximum_memory_used();
if (current_memory_used != last_memory_used)
{
printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used);
last_memory_used = current_memory_used;
}
}
result = 0;
}
messagereceiver_destroy(message_receiver);
link_destroy(link);
session_destroy(session);
connection_destroy(connection);
platform_deinit();
printf("Max memory usage:%lu\r\n", (unsigned long)amqpalloc_get_maximum_memory_used());
printf("Current memory usage:%lu\r\n", (unsigned long)amqpalloc_get_current_memory_used());
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();
#endif
}
return result;
}

Просмотреть файл

@ -0,0 +1,36 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
compileAsC11()
add_executable(message_sender_sample
main.c)
#TODO: link to whatever else the platform has (now for windows it is just ws2_32)
include_directories(.)
if(WIN32)
#windows needs this define
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DGB_MEASURE_MEMORY_FOR_THIS -DGB_DEBUG_ALLOC)
target_link_libraries(message_sender_sample
uamqp
aziotsharedutil
ws2_32
secur32)
if(${use_openssl})
target_link_libraries(message_sender_sample
$ENV{OpenSSLDir}/lib/ssleay32.lib $ENV{OpenSSLDir}/lib/libeay32.lib)
file(COPY $ENV{OpenSSLDir}/bin/libeay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
file(COPY $ENV{OpenSSLDir}/bin/ssleay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
endif()
else()
target_link_libraries(message_sender_sample uamqp aziotsharedutil ssl crypto)
endif()
if(${tlsio_wolfssl})
target_link_libraries(message_sender_sample $ENV{WolfSSLDir}/Debug/wolfssl.lib)
endif()

Просмотреть файл

@ -0,0 +1,183 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdio.h>
#include <stdbool.h>
#include "platform.h"
#include "message_sender.h"
#include "message.h"
#include "messaging.h"
#include "amqpalloc.h"
#include "saslclientio.h"
#include "sasl_plain.h"
#if _WIN32
#include "tlsio_schannel.h"
#else
#ifdef MBED_BUILD_TIMESTAMP
#include "tlsio_wolfssl.h"
#else
#include "tlsio_openssl.h"
#endif
#endif
#include "consolelogger.h"
#include "cbs.h"
#if _WIN32
#include "windows.h"
#endif
/* This sample connects to an Event Hub, authenticates using SASL PLAIN (key name/key) and then it sends 1000 messages */
/* Replace the below settings with your own.*/
#define EH_HOST "<<<Replace with your own EH host (like myeventhub.servicebus.windows.net)>>>"
#define EH_KEY_NAME "<<<Replace with your own key name>>>"
#define EH_KEY "<<<Replace with your own key>>>"
#define EH_NAME "<<<Replace with your event hub name (like my_event_hub)>>>"
static const size_t msg_count = 1000;
static unsigned int sent_messages = 0;
static void on_message_send_complete(const void* context, MESSAGE_SEND_RESULT send_result)
{
(void)send_result;
(void)context;
sent_messages++;
//printf("Sent %lu.\r\n", sent_messages);
}
int main(int argc, char** argv)
{
int result;
amqpalloc_set_memory_tracing_enabled(true);
if (platform_init() != 0)
{
result = -1;
}
else
{
XIO_HANDLE sasl_io;
CONNECTION_HANDLE connection;
SESSION_HANDLE session;
LINK_HANDLE link;
MESSAGE_SENDER_HANDLE message_sender;
MESSAGE_HANDLE message;
size_t last_memory_used = 0;
/* create SASL PLAIN handler */
SASL_PLAIN_CONFIG sasl_plain_config = { EH_KEY_NAME, EH_KEY };
SASL_MECHANISM_HANDLE sasl_mechanism_handle = saslmechanism_create(saslplain_get_interface(), &sasl_plain_config);
XIO_HANDLE tls_io;
/* create the TLS IO */
#if _WIN32
TLSIO_SCHANNEL_CONFIG tls_io_config = { EH_HOST, 5671 };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = tlsio_schannel_get_interface_description();
#else
#ifdef MBED_BUILD_TIMESTAMP
TLSIO_WOLFSSL_CONFIG tls_io_config = { EH_HOST, 5671 };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = tlsio_wolfssl_get_interface_description();
#else
TLSIO_OPENSSL_CONFIG tls_io_config = { EH_HOST, 5671 };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = tlsio_openssl_get_interface_description();
#endif
#endif
tls_io = xio_create(tlsio_interface, &tls_io_config, NULL);
/* create the SASL client IO using the TLS IO */
SASLCLIENTIO_CONFIG sasl_io_config = { tls_io, sasl_mechanism_handle };
sasl_io = xio_create(saslclientio_get_interface_description(), &sasl_io_config, NULL);
/* create the connection, session and link */
connection = connection_create(sasl_io, EH_HOST, "some", NULL, NULL);
session = session_create(connection, NULL, NULL);
session_set_incoming_window(session, 2147483647);
session_set_outgoing_window(session, 65536);
AMQP_VALUE source = messaging_create_source("ingress");
AMQP_VALUE target = messaging_create_target("amqps://" EH_HOST "/" EH_NAME);
link = link_create(session, "sender-link", role_sender, source, target);
link_set_snd_settle_mode(link, sender_settle_mode_settled);
(void)link_set_max_message_size(link, 65536);
amqpvalue_destroy(source);
amqpvalue_destroy(target);
message = message_create();
unsigned char hello[] = { 'H', 'e', 'l', 'l', 'o' };
BINARY_DATA binary_data = { hello, sizeof(hello) };
message_add_body_amqp_data(message, binary_data);
/* create a message sender */
message_sender = messagesender_create(link, NULL, NULL, NULL);
if (messagesender_open(message_sender) == 0)
{
uint32_t i;
#if _WIN32
unsigned long startTime = (unsigned long)GetTickCount64();
#endif
for (i = 0; i < msg_count; i++)
{
(void)messagesender_send(message_sender, message, on_message_send_complete, message);
}
message_destroy(message);
while (true)
{
size_t current_memory_used;
size_t maximum_memory_used;
connection_dowork(connection);
current_memory_used = amqpalloc_get_current_memory_used();
maximum_memory_used = amqpalloc_get_maximum_memory_used();
if (current_memory_used != last_memory_used)
{
printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used);
last_memory_used = current_memory_used;
}
if (sent_messages == msg_count)
{
break;
}
}
#if _WIN32
unsigned long endTime = (unsigned long)GetTickCount64();
printf("Send %lu messages in %lu ms: %.02f msgs/sec\r\n", msg_count, (endTime - startTime), (float)msg_count / ((float)(endTime - startTime) / 1000));
#endif
}
messagesender_destroy(message_sender);
link_destroy(link);
session_destroy(session);
connection_destroy(connection);
xio_destroy(sasl_io);
xio_destroy(tls_io);
saslmechanism_destroy(sasl_mechanism_handle);
platform_deinit();
printf("Max memory usage:%lu\r\n", (unsigned long)amqpalloc_get_maximum_memory_used());
printf("Current memory usage:%lu\r\n", (unsigned long)amqpalloc_get_current_memory_used());
result = 0;
}
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();
#endif
return result;
}

Просмотреть файл

@ -0,0 +1,36 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
compileAsC11()
add_executable(mssbcbs_sample
main.c)
#TODO: link to whatever else the platform has (now for windows it is just ws2_32)
include_directories(.)
if (WIN32)
#windows needs this define
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DGB_MEASURE_MEMORY_FOR_THIS -DGB_DEBUG_ALLOC)
target_link_libraries(mssbcbs_sample
uamqp
aziotsharedutil
ws2_32
secur32)
if(${use_openssl})
target_link_libraries(mssbcbs_sample
$ENV{OpenSSLDir}/lib/ssleay32.lib $ENV{OpenSSLDir}/lib/libeay32.lib)
file(COPY $ENV{OpenSSLDir}/bin/libeay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
file(COPY $ENV{OpenSSLDir}/bin/ssleay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
endif()
else()
target_link_libraries(mssbcbs_sample uamqp aziotsharedutil ssl crypto)
endif()
if(${tlsio_wolfssl})
target_link_libraries(mssbcbs_sample $ENV{WolfSSLDir}/Debug/wolfssl.lib)
endif()

Просмотреть файл

@ -0,0 +1,209 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdio.h>
#include <stdbool.h>
#include "platform.h"
#include "message_sender.h"
#include "message.h"
#include "messaging.h"
#include "amqpalloc.h"
#include "saslclientio.h"
#include "sasl_mssbcbs.h"
#if _WIN32
#include "tlsio_schannel.h"
#else
#ifdef MBED_BUILD_TIMESTAMP
#include "tlsio_wolfssl.h"
#else
#include "tlsio_openssl.h"
#endif
#endif
#include "consolelogger.h"
#include "cbs.h"
/* This sample connects to an IoTHub, authenticates using a CBS token and sends one message */
/* Replace the below settings with your own.*/
#define IOT_HUB_HOST "<<<Replace with your own IoTHub host (like myiothub.azure-devices.net)>>>"
#define IOT_HUB_DEVICE_NAME "<<<Replace with your device Id (like test_Device)>>>"
#define IOT_HUB_DEVICE_SAS_TOKEN "<<<Replace with your own device SAS token (needs to be generated)>>>"
static unsigned int sent_messages = 0;
static const size_t msg_count = 1;
static bool auth = false;
static void on_amqp_management_state_chaged(void* context, AMQP_MANAGEMENT_STATE new_amqp_management_state, AMQP_MANAGEMENT_STATE previous_amqp_management_state)
{
(void)context;
(void)previous_amqp_management_state;
if (new_amqp_management_state == AMQP_MANAGEMENT_STATE_IDLE)
{
printf("Disconnected.\r\n");
}
}
static void on_message_send_complete(const void* context, MESSAGE_SEND_RESULT send_result)
{
(void)send_result;
(void)context;
printf("Sent.\r\n");
sent_messages++;
}
static void on_cbs_operation_complete(void* context, CBS_OPERATION_RESULT cbs_operation_result, unsigned int status_code, const char* status_description)
{
(void)context, status_code, status_description;
if (cbs_operation_result == CBS_OPERATION_RESULT_OK)
{
auth = true;
}
}
int main(int argc, char** argv)
{
int result;
amqpalloc_set_memory_tracing_enabled(true);
if (platform_init() != 0)
{
result = -1;
}
else
{
XIO_HANDLE sasl_io;
CONNECTION_HANDLE connection;
SESSION_HANDLE session;
LINK_HANDLE link;
MESSAGE_SENDER_HANDLE message_sender;
MESSAGE_HANDLE message;
size_t last_memory_used = 0;
/* create SASL MSSBCBS handler */
SASL_MECHANISM_HANDLE sasl_mechanism_handle = saslmechanism_create(saslmssbcbs_get_interface(), NULL);
XIO_HANDLE tls_io;
/* create the TLS IO */
#if _WIN32
TLSIO_SCHANNEL_CONFIG tls_io_config = { IOT_HUB_HOST, 5671 };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = tlsio_schannel_get_interface_description();
#else
#ifdef MBED_BUILD_TIMESTAMP
TLSIO_WOLFSSL_CONFIG tls_io_config = { IOT_HUB_HOST, 5671 };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = tlsio_wolfssl_get_interface_description();
#else
TLSIO_OPENSSL_CONFIG tls_io_config = { IOT_HUB_HOST, 5671 };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = tlsio_openssl_get_interface_description();
#endif
#endif
tls_io = xio_create(tlsio_interface, &tls_io_config, NULL);
/* create the SASL client IO using the TLS IO */
SASLCLIENTIO_CONFIG sasl_io_config = { tls_io, sasl_mechanism_handle };
sasl_io = xio_create(saslclientio_get_interface_description(), &sasl_io_config, NULL);
/* create the connection, session and link */
connection = connection_create(sasl_io, IOT_HUB_HOST, "some", NULL, NULL);
session = session_create(connection, NULL, NULL);
session_set_incoming_window(session, 2147483647);
session_set_outgoing_window(session, 2);
CBS_HANDLE cbs = cbs_create(session, NULL, NULL);
if (cbs_open(cbs) == 0)
{
(void)cbs_put_token(cbs, "servicebus.windows.net:sastoken", IOT_HUB_HOST "/devices/" IOT_HUB_DEVICE_NAME, IOT_HUB_DEVICE_SAS_TOKEN, on_cbs_operation_complete, cbs);
while (!auth)
{
size_t current_memory_used;
size_t maximum_memory_used;
connection_dowork(connection);
current_memory_used = amqpalloc_get_current_memory_used();
maximum_memory_used = amqpalloc_get_maximum_memory_used();
if (current_memory_used != last_memory_used)
{
printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used);
last_memory_used = current_memory_used;
}
}
}
AMQP_VALUE source = messaging_create_source("ingress");
AMQP_VALUE target = messaging_create_target("amqps://" IOT_HUB_HOST "/devices/" IOT_HUB_DEVICE_NAME "/messages/events");
link = link_create(session, "sender-link", role_sender, source, target);
(void)link_set_max_message_size(link, 65536);
amqpvalue_destroy(source);
amqpvalue_destroy(target);
message = message_create();
unsigned char hello[] = { 'H', 'e', 'l', 'l', 'o' };
BINARY_DATA binary_data = { hello, sizeof(hello) };
message_add_body_amqp_data(message, binary_data);
/* create a message sender */
message_sender = messagesender_create(link, NULL, NULL, NULL);
if (messagesender_open(message_sender) == 0)
{
uint32_t i;
for (i = 0; i < msg_count; i++)
{
(void)messagesender_send(message_sender, message, on_message_send_complete, message);
}
message_destroy(message);
while (true)
{
size_t current_memory_used;
size_t maximum_memory_used;
connection_dowork(connection);
current_memory_used = amqpalloc_get_current_memory_used();
maximum_memory_used = amqpalloc_get_maximum_memory_used();
if (current_memory_used != last_memory_used)
{
printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used);
last_memory_used = current_memory_used;
}
if (sent_messages == msg_count)
{
break;
}
}
}
cbs_destroy(cbs);
messagesender_destroy(message_sender);
link_destroy(link);
session_destroy(session);
connection_destroy(connection);
xio_destroy(sasl_io);
xio_destroy(tls_io);
saslmechanism_destroy(sasl_mechanism_handle);
platform_deinit();
printf("Max memory usage:%lu\r\n", (unsigned long)amqpalloc_get_maximum_memory_used());
printf("Current memory usage:%lu\r\n", (unsigned long)amqpalloc_get_current_memory_used());
}
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();
#endif
return 0;
}

Просмотреть файл

@ -0,0 +1,30 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
compileAsC11()
add_executable(websockets_sample
main.c
iothub_certs.h
iothub_certs.c)
#TODO: link to whatever else the platform has (now for windows it is just ws2_32)
include_directories(.)
if(WIN32)
#windows needs this define
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DGB_MEASURE_MEMORY_FOR_THIS -DGB_DEBUG_ALLOC)
target_link_libraries(websockets_sample
uamqp
ws2_32
$ENV{OpenSSLDir}/lib/ssleay32.lib $ENV{OpenSSLDir}/lib/libeay32.lib
aziotsharedutil.lib
$ENV{WSDir}/build/lib/Debug/websockets_static.lib
$ENV{WSDir}/build/lib/Debug/zlib_internal.lib)
file(COPY $ENV{OpenSSLDir}/bin/libeay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
file(COPY $ENV{OpenSSLDir}/bin/ssleay32.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug)
else()
target_link_libraries(websockets_sample uamqp aziotsharedutil ssl crypto)
endif()

Просмотреть файл

@ -0,0 +1,99 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include "iothub_certs.h"
const char iothub_certs[] =
/* Baltimore */
"-----BEGIN CERTIFICATE-----\r\n"
"MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\r\n"
"RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\r\n"
"VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\r\n"
"DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\r\n"
"ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\r\n"
"VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\r\n"
"mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\r\n"
"IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\r\n"
"mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\r\n"
"XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\r\n"
"dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\r\n"
"jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\r\n"
"BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\r\n"
"DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\r\n"
"9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\r\n"
"jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\r\n"
"Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\r\n"
"ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\r\n"
"R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\r\n"
"-----END CERTIFICATE-----\r\n"
/* MSIT */
"-----BEGIN CERTIFICATE-----\r\n"
"MIIFhjCCBG6gAwIBAgIEByeaqTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJ\r\n"
"RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\r\n"
"VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTEzMTIxOTIwMDczMloX\r\n"
"DTE3MTIxOTIwMDY1NVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n\r\n"
"dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y\r\n"
"YXRpb24xFTATBgNVBAsTDE1pY3Jvc29mdCBJVDEeMBwGA1UEAxMVTWljcm9zb2Z0\r\n"
"IElUIFNTTCBTSEEyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0eg3\r\n"
"p3aKcEsZ8CA3CSQ3f+r7eOYFumqtTicN/HJq2WwhxGQRlXMQClwle4hslAT9x9uu\r\n"
"e9xKCLM+FvHQrdswbdcaHlK1PfBHGQPifaa9VxM/VOo6o7F3/ELwY0lqkYAuMEnA\r\n"
"iusrr/466wddBvfp/YQOkb0JICnobl0JzhXT5+/bUOtE7xhXqwQdvDH593sqE8/R\r\n"
"PVGvG8W1e+ew/FO7mudj3kEztkckaV24Rqf/ravfT3p4JSchJjTKAm43UfDtWBpg\r\n"
"lPbEk9jdMCQl1xzrGZQ1XZOyrqopg3PEdFkFUmed2mdROQU6NuryHnYrFK7sPfkU\r\n"
"mYsHbrznDFberL6u23UykJ5jvXS/4ArK+DSWZ4TN0UI4eMeZtgzOtg/pG8v0Wb4R\r\n"
"DsssMsj6gylkeTyLS/AydGzzk7iWa11XWmjBzAx5ihne9UkCXgiAAYkMMs3S1pbV\r\n"
"S6Dz7L+r9H2zobl82k7X5besufIlXwHLjJaoKK7BM1r2PwiQ3Ov/OdgmyBKdHJqq\r\n"
"qcAWjobtZ1KWAH8Nkj092XA25epCbx+uleVbXfjQOsfU3neG0PyeTuLiuKloNwnE\r\n"
"OeOFuInzH263bR9KLxgJb95KAY8Uybem7qdjnzOkVHxCg2i4pd+/7LkaXRM72a1o\r\n"
"/SAKVZEhZPnXEwGgCF1ZiRtEr6SsxwUQ+kFKqPsCAwEAAaOCASAwggEcMBIGA1Ud\r\n"
"EwEB/wQIMAYBAf8CAQAwUwYDVR0gBEwwSjBIBgkrBgEEAbE+AQAwOzA5BggrBgEF\r\n"
"BQcCARYtaHR0cDovL2N5YmVydHJ1c3Qub21uaXJvb3QuY29tL3JlcG9zaXRvcnku\r\n"
"Y2ZtMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH\r\n"
"AwIwHwYDVR0jBBgwFoAU5Z1ZMIJHWMys+ghUNoZ7OrUETfAwQgYDVR0fBDswOTA3\r\n"
"oDWgM4YxaHR0cDovL2NkcDEucHVibGljLXRydXN0LmNvbS9DUkwvT21uaXJvb3Qy\r\n"
"MDI1LmNybDAdBgNVHQ4EFgQUUa8kJpz0aCJXgCYrO0ZiFXsezKUwDQYJKoZIhvcN\r\n"
"AQELBQADggEBAHaFxSMxH7Rz6qC8pe3fRUNqf2kgG4Cy+xzdqn+I0zFBNvf7+2ut\r\n"
"mIx4H50RZzrNS+yovJ0VGcQ7C6eTzuj8nVvoH8tWrnZDK8cTUXdBqGZMX6fR16p1\r\n"
"xRspTMn0baFeoYWTFsLLO6sUfUT92iUphir+YyDK0gvCNBW7r1t/iuCq7UWm6nnb\r\n"
"2DVmVEPeNzPR5ODNV8pxsH3pFndk6FmXudUu0bSR2ndx80oPSNI0mWCVN6wfAc0Q\r\n"
"negqpSDHUJuzbEl4K1iSZIm4lTaoNKrwQdKVWiRUl01uBcSVrcR6ozn7eQaKm6ZP\r\n"
"2SL6RE4288kPpjnngLJev7050UblVUfbvG4=\r\n"
"-----END CERTIFICATE-----\r\n"
/* *.azure-devices.net */
"-----BEGIN CERTIFICATE-----\r\n"
"MIIGcjCCBFqgAwIBAgITWgABtrNbz7vBeV0QWwABAAG2szANBgkqhkiG9w0BAQsF\r\n"
"ADCBizELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT\r\n"
"B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEVMBMGA1UE\r\n"
"CxMMTWljcm9zb2Z0IElUMR4wHAYDVQQDExVNaWNyb3NvZnQgSVQgU1NMIFNIQTIw\r\n"
"HhcNMTUwODI3MDMxODA0WhcNMTcwODI2MDMxODA0WjAeMRwwGgYDVQQDDBMqLmF6\r\n"
"dXJlLWRldmljZXMubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\r\n"
"nXC/qBUdlnfIm5K3HYu0o/Mb5tNNcsr0xy4Do0Puwq2W1tz0ZHvIIS9VOANhkNCb\r\n"
"VyOncnP6dvmM/rYYKth/NQ8RUiZOYlROZ0SYC8cvxq9WOln4GXtEU8vNVqJbYrJj\r\n"
"rPMHfxqLzTE/0ZnQffnDT3iMUE9kFLHow0YgaSRU0KZsc9KAROmzBzu+QIB1WGKX\r\n"
"D7CN361tG1UuN68Bz7MSnbgk98Z+DjDxfusoDhiiy/Y9MLOJMt4WIy5BqL3lfLnn\r\n"
"r+JLqmpiFuyVUDacFQDprYJ1/AFgcsKYu/ydmASARPzqJhOGaC2sZP0U5oBOoBzI\r\n"
"bz4tfn8Bi0kJKmS53mQt+wIDAQABo4ICOTCCAjUwCwYDVR0PBAQDAgSwMB0GA1Ud\r\n"
"JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUKpYehBSNA53Oxivn\r\n"
"aLCz3+eFUJ0wXQYDVR0RBFYwVIITKi5henVyZS1kZXZpY2VzLm5ldIIaKi5hbXFw\r\n"
"d3MuYXp1cmUtZGV2aWNlcy5uZXSCISouc3UubWFuYWdlbWVudC1henVyZS1kZXZp\r\n"
"Y2VzLm5ldDAfBgNVHSMEGDAWgBRRryQmnPRoIleAJis7RmIVex7MpTB9BgNVHR8E\r\n"
"djB0MHKgcKBuhjZodHRwOi8vbXNjcmwubWljcm9zb2Z0LmNvbS9wa2kvbXNjb3Jw\r\n"
"L2NybC9tc2l0d3d3Mi5jcmyGNGh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kv\r\n"
"bXNjb3JwL2NybC9tc2l0d3d3Mi5jcmwwcAYIKwYBBQUHAQEEZDBiMDwGCCsGAQUF\r\n"
"BzAChjBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL21zY29ycC9tc2l0d3d3\r\n"
"Mi5jcnQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLm1zb2NzcC5jb20wTgYDVR0g\r\n"
"BEcwRTBDBgkrBgEEAYI3KgEwNjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5taWNy\r\n"
"b3NvZnQuY29tL3BraS9tc2NvcnAvY3BzADAnBgkrBgEEAYI3FQoEGjAYMAoGCCsG\r\n"
"AQUFBwMBMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4ICAQCrjzOSW+X6v+UC\r\n"
"u+JkYyuypXN14pPLcGFbknJWj6DAyFWXKC8ihIYdtf/szWIO7VooplSTZ05u/JYu\r\n"
"ZYh7fAw27qih9CLhhfncXi5yzjgLMlD0mlbORvMJR/nMl7Yh1ki9GyLnpOqMmO+E\r\n"
"yTpOiE07Uyt2uWelLHjMY8kwy2bSRXIp7/+A8qHRaIIdXNtAKIK5jo068BJpo77h\r\n"
"4PljCb9JFdEt6sAKKuaP86Y+8oRZ7YzU4TLDCiK8P8n/gQXH0vvhOE/O0n7gWPqB\r\n"
"n8KxsnRicop6tB6GZy32Stn8w0qktmQNXOGU+hp8OL6irULWZw/781po6d78nmwk\r\n"
"1IFl2TB4+jgyblvJdTM0rx8vPf3F2O2kgsRNs9M5qCI7m+he43Bhue0Fj/h3oIIo\r\n"
"Qx7X/uqc8j3VTNE9hf2A4wksSRgRydjAYoo+bduNagC5s7Eucb4mBG0MMk7HAQU9\r\n"
"m/gyaxqth6ygDLK58wojSV0i4RiU01qZkHzqIWv5FhhMjbFwyKEc6U35Ps7kP/1O\r\n"
"fdGm13ONaYqDl44RyFsLFFiiDYxZFDSsKM0WDxbl9ULAlVc3WR85kEBK6I+pSQj+\r\n"
"7/Z5z2zTz9qOFWgB15SegTbjSR7uk9mEVnj9KDlGtG8W1or0EGrrEDP2CMsp0oEj\r\n"
"VTJbZAxEaZ3cVCKva5sQUxFMjwG32g==\r\n"
"-----END CERTIFICATE-----\r\n";

Просмотреть файл

@ -0,0 +1,9 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef IOTHUB_CERTS_H
#define IOTHUB_CERTS_H
extern const char iothub_certs[];
#endif /* IOTHUB_CERTS_H */

Просмотреть файл

@ -0,0 +1,193 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdio.h>
#include <stdbool.h>
#include "platform.h"
#include "message_sender.h"
#include "message.h"
#include "messaging.h"
#include "amqpalloc.h"
#include "saslio.h"
#include "sasl_mssbcbs.h"
#include "wsio.h"
#include "consolelogger.h"
#include "cbs.h"
#include "iothub_certs.h"
/* Replace the below settings with your own.*/
#define IOT_HUB_HOST "<<<Replace with your own IoTHub host (like myiothub.azure-devices.net)>>>"
#define IOT_HUB_DEVICE_NAME "<<<Replace with your device Id (like test_Device)>>>"
#define IOT_HUB_DEVICE_SAS_TOKEN "<<<Replace with your own device SAS token (needs to be generated)>>>"
static const size_t msg_count = 1000;
static unsigned int sent_messages = 0;
static bool auth = false;
static void on_amqp_management_state_chaged(void* context, AMQP_MANAGEMENT_STATE new_amqp_management_state, AMQP_MANAGEMENT_STATE previous_amqp_management_state)
{
(void)context, previous_amqp_management_state;
if (new_amqp_management_state == AMQP_MANAGEMENT_STATE_IDLE)
{
printf("Disconnected.\r\n");
}
}
void on_message_send_complete(const void* context, MESSAGE_SEND_RESULT send_result)
{
(void)send_result;
(void)context;
printf("Sent.\r\n");
sent_messages++;
}
void on_cbs_operation_complete(void* context, CBS_OPERATION_RESULT cbs_operation_result, unsigned int status_code, const char* status_description)
{
(void)context, status_code, status_description;
if (cbs_operation_result == CBS_OPERATION_RESULT_OK)
{
auth = true;
}
}
int main(int argc, char** argv)
{
int result;
amqpalloc_set_memory_tracing_enabled(true);
if (platform_init() != 0)
{
result = -1;
}
else
{
XIO_HANDLE sasl_io;
CONNECTION_HANDLE connection;
SESSION_HANDLE session;
LINK_HANDLE link;
MESSAGE_SENDER_HANDLE message_sender;
MESSAGE_HANDLE message;
size_t last_memory_used = 0;
/* create SASL MSSBCBS handler */
SASL_MECHANISM_HANDLE sasl_mechanism_handle = saslmechanism_create(saslmssbcbs_get_interface(), NULL);
XIO_HANDLE ws_io;
/* create the TLS IO */
WSIO_CONFIG ws_io_config = { IOT_HUB_HOST, 443, "AMQPWSB10", "/$iothub/websocket", true, iothub_certs };
const IO_INTERFACE_DESCRIPTION* tlsio_interface = wsio_get_interface_description();
ws_io = xio_create(tlsio_interface, &ws_io_config, NULL);
/* create the SASL IO using the WS IO */
SASLIO_CONFIG sasl_io_config = { ws_io, sasl_mechanism_handle };
sasl_io = xio_create(saslio_get_interface_description(), &sasl_io_config, NULL);
/* create the connection, session and link */
connection = connection_create(sasl_io, IOT_HUB_HOST, "some");
session = session_create(connection);
session_set_incoming_window(session, 2147483647);
session_set_outgoing_window(session, 65536);
CBS_HANDLE cbs = cbs_create(session, NULL, NULL);
if (cbs_open(cbs) == 0)
{
(void)cbs_put_token(cbs, "servicebus.windows.net:sastoken", IOT_HUB_HOST "/devices/" IOT_HUB_DEVICE_NAME, IOT_HUB_DEVICE_SAS_TOKEN, on_cbs_operation_complete, cbs);
while (!auth)
{
size_t current_memory_used;
size_t maximum_memory_used;
connection_dowork(connection);
current_memory_used = amqpalloc_get_current_memory_used();
maximum_memory_used = amqpalloc_get_maximum_memory_used();
if (current_memory_used != last_memory_used)
{
printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used);
last_memory_used = current_memory_used;
}
}
}
AMQP_VALUE source = messaging_create_source("ingress");
AMQP_VALUE target = messaging_create_target("amqps://" IOT_HUB_HOST "/devices/" IOT_HUB_DEVICE_NAME "/messages/events");
link = link_create(session, "sender-link", role_sender, source, target);
(void)link_set_max_message_size(link, 65536);
amqpvalue_destroy(source);
amqpvalue_destroy(target);
message = message_create();
unsigned char hello[5] = { 'h', 'e', 'l', 'l', 'o' };
BINARY_DATA binary_data = { hello, sizeof(hello) };
message_add_body_amqp_data(message, binary_data);
/* create a message sender */
message_sender = messagesender_create(link, NULL, NULL, NULL);
if (messagesender_open(message_sender) == 0)
{
uint32_t i;
for (i = 0; i < msg_count; i++)
{
(void)messagesender_send(message_sender, message, on_message_send_complete, message);
}
message_destroy(message);
while (true)
{
size_t current_memory_used;
size_t maximum_memory_used;
connection_dowork(connection);
current_memory_used = amqpalloc_get_current_memory_used();
maximum_memory_used = amqpalloc_get_maximum_memory_used();
if (current_memory_used != last_memory_used)
{
printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used);
last_memory_used = current_memory_used;
}
if (sent_messages == msg_count)
{
break;
}
}
}
cbs_destroy(cbs);
messagesender_destroy(message_sender);
link_destroy(link);
session_destroy(session);
connection_destroy(connection);
xio_destroy(sasl_io);
xio_destroy(ws_io);
saslmechanism_destroy(sasl_mechanism_handle);
platform_deinit();
printf("Max memory usage:%lu\r\n", (unsigned long)amqpalloc_get_maximum_memory_used());
printf("Current memory usage:%lu\r\n", (unsigned long)amqpalloc_get_current_memory_used());
result = 0;
}
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();
#endif
return result;
}

14028
src/amqp_definitions.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

337
src/amqp_frame_codec.c Normal file
Просмотреть файл

@ -0,0 +1,337 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "amqp_frame_codec.h"
#include "frame_codec.h"
#include "amqpalloc.h"
#include "amqpvalue.h"
typedef enum AMQP_FRAME_DECODE_STATE_TAG
{
AMQP_FRAME_DECODE_FRAME,
AMQP_FRAME_DECODE_ERROR
} AMQP_FRAME_DECODE_STATE;
typedef struct AMQP_FRAME_CODEC_INSTANCE_TAG
{
FRAME_CODEC_HANDLE frame_codec;
/* decode */
AMQP_FRAME_RECEIVED_CALLBACK frame_received_callback;
AMQP_EMPTY_FRAME_RECEIVED_CALLBACK empty_frame_received_callback;
AMQP_FRAME_CODEC_ERROR_CALLBACK error_callback;
void* callback_context;
AMQPVALUE_DECODER_HANDLE decoder;
AMQP_FRAME_DECODE_STATE decode_state;
AMQP_VALUE decoded_performative;
} AMQP_FRAME_CODEC_INSTANCE;
static void amqp_value_decoded(void* context, AMQP_VALUE decoded_value)
{
AMQP_FRAME_CODEC_INSTANCE* amqp_frame_codec_instance = (AMQP_FRAME_CODEC_INSTANCE*)context;
uint64_t performative_descriptor_ulong;
AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(decoded_value);
/* Codes_SRS_AMQP_FRAME_CODEC_01_060: [If any error occurs while decoding a frame, the decoder shall switch to an error state where decoding shall not be possible anymore.] */
if ((descriptor == NULL) ||
(amqpvalue_get_ulong(descriptor, &performative_descriptor_ulong) != 0) ||
/* Codes_SRS_AMQP_FRAME_CODEC_01_003: [The performative MUST be one of those defined in section 2.7 and is encoded as a described type in the AMQP type system.] */
(performative_descriptor_ulong < AMQP_OPEN) ||
(performative_descriptor_ulong > AMQP_CLOSE))
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_060: [If any error occurs while decoding a frame, the decoder shall switch to an error state where decoding shall not be possible anymore.] */
amqp_frame_codec_instance->decode_state = AMQP_FRAME_DECODE_ERROR;
}
else
{
amqp_frame_codec_instance->decoded_performative = decoded_value;
}
}
static void frame_received(void* context, const unsigned char* type_specific, uint32_t type_specific_size, const unsigned char* frame_body, uint32_t frame_body_size)
{
AMQP_FRAME_CODEC_INSTANCE* amqp_frame_codec_instance = (AMQP_FRAME_CODEC_INSTANCE*)context;
uint16_t channel;
switch (amqp_frame_codec_instance->decode_state)
{
default:
/* Codes_SRS_AMQP_FRAME_CODEC_01_050: [All subsequent decoding shall fail and no AMQP frames shall be indicated from that point on to the consumers of amqp_frame_codec.] */
case AMQP_FRAME_DECODE_ERROR:
break;
case AMQP_FRAME_DECODE_FRAME:
/* Codes_SRS_AMQP_FRAME_CODEC_01_049: [If not enough type specific bytes are received to decode the channel number, the decoding shall stop with an error.] */
if (type_specific_size < 2)
{
amqp_frame_codec_instance->decode_state = AMQP_FRAME_DECODE_ERROR;
/* Codes_SRS_AMQP_FRAME_CODEC_01_069: [If any error occurs while decoding a frame, the decoder shall indicate the error by calling the amqp_frame_codec_error_callback and passing to it the callback context argument that was given in amqp_frame_codec_create.] */
amqp_frame_codec_instance->error_callback(amqp_frame_codec_instance->callback_context);
}
else
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_001: [Bytes 6 and 7 of an AMQP frame contain the channel number ] */
channel = ((uint16_t)type_specific[0]) << 8;
channel += type_specific[1];
if (frame_body_size == 0)
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_048: [When a frame header is received from frame_codec and the frame payload size is 0, empty_frame_received_callback shall be invoked, while passing the channel number as argument.] */
/* Codes_SRS_AMQP_FRAME_CODEC_01_007: [An AMQP frame with no body MAY be used to generate artificial traffic as needed to satisfy any negotiated idle timeout interval ] */
amqp_frame_codec_instance->empty_frame_received_callback(amqp_frame_codec_instance->callback_context, channel);
}
else
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_051: [If the frame payload is greater than 0, amqp_frame_codec shall decode the performative as a described AMQP type.] */
/* Codes_SRS_AMQP_FRAME_CODEC_01_002: [The frame body is defined as a performative followed by an opaque payload.] */
amqp_frame_codec_instance->decoded_performative = NULL;
while ((frame_body_size > 0) &&
(amqp_frame_codec_instance->decoded_performative == NULL) &&
(amqp_frame_codec_instance->decode_state != AMQP_FRAME_DECODE_ERROR))
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_052: [Decoding the performative shall be done by feeding the bytes to the decoder create in amqp_frame_codec_create.] */
if (amqpvalue_decode_bytes(amqp_frame_codec_instance->decoder, frame_body, 1) != 0)
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_060: [If any error occurs while decoding a frame, the decoder shall switch to an error state where decoding shall not be possible anymore.] */
amqp_frame_codec_instance->decode_state = AMQP_FRAME_DECODE_ERROR;
}
else
{
frame_body_size--;
frame_body++;
}
}
if (amqp_frame_codec_instance->decode_state == AMQP_FRAME_DECODE_ERROR)
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_069: [If any error occurs while decoding a frame, the decoder shall indicate the error by calling the amqp_frame_codec_error_callback and passing to it the callback context argument that was given in amqp_frame_codec_create.] */
amqp_frame_codec_instance->error_callback(amqp_frame_codec_instance->callback_context);
}
else
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_004: [The remaining bytes in the frame body form the payload for that frame.] */
/* Codes_SRS_AMQP_FRAME_CODEC_01_067: [When the performative is decoded, the rest of the frame_bytes shall not be given to the AMQP decoder, but they shall be buffered so that later they are given to the frame_received callback.] */
/* Codes_SRS_AMQP_FRAME_CODEC_01_054: [Once the performative is decoded and all frame payload bytes are received, the callback frame_received_callback shall be called.] */
/* Codes_SRS_AMQP_FRAME_CODEC_01_068: [A pointer to all the payload bytes shall also be passed to frame_received_callback.] */
amqp_frame_codec_instance->frame_received_callback(amqp_frame_codec_instance->callback_context, channel, amqp_frame_codec_instance->decoded_performative, frame_body, frame_body_size);
}
}
}
break;
}
}
static int encode_bytes(void* context, const unsigned char* bytes, size_t length)
{
PAYLOAD* payload = (PAYLOAD*)context;
(void)memcpy((unsigned char*)payload->bytes + payload->length, bytes, length);
payload->length += length;
return 0;
}
/* Codes_SRS_AMQP_FRAME_CODEC_01_011: [amqp_frame_codec_create shall create an instance of an amqp_frame_codec and return a non-NULL handle to it.] */
AMQP_FRAME_CODEC_HANDLE amqp_frame_codec_create(FRAME_CODEC_HANDLE frame_codec, AMQP_FRAME_RECEIVED_CALLBACK frame_received_callback,
AMQP_EMPTY_FRAME_RECEIVED_CALLBACK empty_frame_received_callback, AMQP_FRAME_CODEC_ERROR_CALLBACK amqp_frame_codec_error_callback, void* callback_context)
{
AMQP_FRAME_CODEC_INSTANCE* result;
/* Codes_SRS_AMQP_FRAME_CODEC_01_012: [If any of the arguments frame_codec, frame_received_callback, amqp_frame_codec_error_callback or empty_frame_received_callback is NULL, amqp_frame_codec_create shall return NULL.] */
if ((frame_codec == NULL) ||
(frame_received_callback == NULL) ||
(empty_frame_received_callback == NULL) ||
(amqp_frame_codec_error_callback == NULL))
{
result = NULL;
}
else
{
result = (AMQP_FRAME_CODEC_INSTANCE*)amqpalloc_malloc(sizeof(AMQP_FRAME_CODEC_INSTANCE));
/* Codes_SRS_AMQP_FRAME_CODEC_01_020: [If allocating memory for the new amqp_frame_codec fails, then amqp_frame_codec_create shall fail and return NULL.] */
if (result != NULL)
{
result->frame_codec = frame_codec;
result->frame_received_callback = frame_received_callback;
result->empty_frame_received_callback = empty_frame_received_callback;
result->error_callback = amqp_frame_codec_error_callback;
result->callback_context = callback_context;
result->decode_state = AMQP_FRAME_DECODE_FRAME;
/* Codes_SRS_AMQP_FRAME_CODEC_01_018: [amqp_frame_codec_create shall create a decoder to be used for decoding AMQP values.] */
result->decoder = amqpvalue_decoder_create(amqp_value_decoded, result);
if (result->decoder == NULL)
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_019: [If creating the decoder fails, amqp_frame_codec_create shall fail and return NULL.] */
amqpalloc_free(result);
result = NULL;
}
else
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_013: [amqp_frame_codec_create shall subscribe for AMQP frames with the given frame_codec.] */
if (frame_codec_subscribe(frame_codec, FRAME_TYPE_AMQP, frame_received, result) != 0)
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_014: [If subscribing for AMQP frames fails, amqp_frame_codec_create shall fail and return NULL.] */
amqpvalue_decoder_destroy(result->decoder);
amqpalloc_free(result);
result = NULL;
}
}
}
}
return result;
}
void amqp_frame_codec_destroy(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec)
{
if (amqp_frame_codec != NULL)
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_017: [amqp_frame_codec_destroy shall unsubscribe from receiving AMQP frames from the frame_codec that was passed to amqp_frame_codec_create.] */
(void)frame_codec_unsubscribe(amqp_frame_codec->frame_codec, FRAME_TYPE_AMQP);
/* Codes_SRS_AMQP_FRAME_CODEC_01_021: [The decoder created in amqp_frame_codec_create shall be destroyed by amqp_frame_codec_destroy.] */
amqpvalue_decoder_destroy(amqp_frame_codec->decoder);
/* Codes_SRS_AMQP_FRAME_CODEC_01_015: [amqp_frame_codec_destroy shall free all resources associated with the amqp_frame_codec instance.] */
amqpalloc_free(amqp_frame_codec);
}
}
int amqp_frame_codec_encode_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel, const AMQP_VALUE performative, const PAYLOAD* payloads, size_t payload_count, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context)
{
int result;
/* Codes_SRS_AMQP_FRAME_CODEC_01_024: [If frame_codec, performative or on_bytes_encoded is NULL, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
if ((amqp_frame_codec == NULL) ||
(performative == NULL) ||
(on_bytes_encoded == NULL))
{
result = __LINE__;
}
else
{
AMQP_VALUE descriptor;
uint64_t performative_ulong;
size_t encoded_size;
if (((descriptor = amqpvalue_get_inplace_descriptor(performative)) == NULL) ||
(amqpvalue_get_ulong(descriptor, &performative_ulong) != 0) ||
/* Codes_SRS_AMQP_FRAME_CODEC_01_008: [The performative MUST be one of those defined in section 2.7 and is encoded as a described type in the AMQP type system.] */
(performative_ulong < AMQP_OPEN) ||
(performative_ulong > AMQP_CLOSE))
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_029: [If any error occurs during encoding, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
result = __LINE__;
}
/* Codes_SRS_AMQP_FRAME_CODEC_01_027: [The encoded size of the performative and its fields shall be obtained by calling amqpvalue_get_encoded_size.] */
else if (amqpvalue_get_encoded_size(performative, &encoded_size) != 0)
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_029: [If any error occurs during encoding, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
result = __LINE__;
}
else
{
unsigned char* amqp_performative_bytes = (unsigned char*)amqpalloc_malloc(encoded_size);
if (amqp_performative_bytes == NULL)
{
result = __LINE__;
}
else
{
PAYLOAD* new_payloads = (PAYLOAD*)amqpalloc_malloc(sizeof(PAYLOAD) * (payload_count + 1));
if (new_payloads == NULL)
{
result = __LINE__;
}
else
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_070: [The payloads argument for frame_codec_encode_frame shall be made of the payload for the encoded performative and the payloads passed to amqp_frame_codec_encode_frame.] */
/* Codes_SRS_AMQP_FRAME_CODEC_01_028: [The encode result for the performative shall be placed in a PAYLOAD structure.] */
new_payloads[0].bytes = amqp_performative_bytes;
new_payloads[0].length = 0;
if (payload_count > 0)
{
(void)memcpy(new_payloads + 1, payloads, sizeof(PAYLOAD) * payload_count);
}
if (amqpvalue_encode(performative, encode_bytes, &new_payloads[0]) != 0)
{
result = __LINE__;
}
else
{
unsigned char channel_bytes[2] =
{
channel >> 8,
channel & 0xFF
};
/* Codes_SRS_AMQP_FRAME_CODEC_01_005: [Bytes 6 and 7 of an AMQP frame contain the channel number ] */
/* Codes_SRS_AMQP_FRAME_CODEC_01_025: [amqp_frame_codec_encode_frame shall encode the frame header by using frame_codec_encode_frame.] */
/* Codes_SRS_AMQP_FRAME_CODEC_01_006: [The frame body is defined as a performative followed by an opaque payload.] */
if (frame_codec_encode_frame(amqp_frame_codec->frame_codec, FRAME_TYPE_AMQP, new_payloads, payload_count + 1, channel_bytes, sizeof(channel_bytes), on_bytes_encoded, callback_context) != 0)
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_029: [If any error occurs during encoding, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
result = __LINE__;
}
else
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_022: [amqp_frame_codec_begin_encode_frame shall encode the frame header and AMQP performative in an AMQP frame and on success it shall return 0.] */
result = 0;
}
}
amqpalloc_free(new_payloads);
}
amqpalloc_free(amqp_performative_bytes);
}
}
}
return result;
}
/* Codes_SRS_AMQP_FRAME_CODEC_01_042: [amqp_frame_codec_encode_empty_frame shall encode a frame with no payload.] */
/* Codes_SRS_AMQP_FRAME_CODEC_01_010: [An AMQP frame with no body MAY be used to generate artificial traffic as needed to satisfy any negotiated idle timeout interval ] */
int amqp_frame_codec_encode_empty_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context)
{
int result;
/* Codes_SRS_AMQP_FRAME_CODEC_01_045: [If amqp_frame_codec is NULL, amqp_frame_codec_encode_empty_frame shall fail and return a non-zero value.] */
if (amqp_frame_codec == NULL)
{
result = __LINE__;
}
else
{
unsigned char channel_bytes[2] =
{
channel >> 8,
channel & 0xFF
};
/* Codes_SRS_AMQP_FRAME_CODEC_01_044: [amqp_frame_codec_encode_empty_frame shall use frame_codec_encode_frame to encode the frame.] */
if (frame_codec_encode_frame(amqp_frame_codec->frame_codec, FRAME_TYPE_AMQP, NULL, 0, channel_bytes, sizeof(channel_bytes), on_bytes_encoded, callback_context) != 0)
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_046: [If encoding fails in any way, amqp_frame_codec_encode_empty_frame shall fail and return a non-zero value.] */
result = __LINE__;
}
else
{
/* Codes_SRS_AMQP_FRAME_CODEC_01_043: [On success, amqp_frame_codec_encode_empty_frame shall return 0.] */
result = 0;
}
}
return result;
}

659
src/amqp_management.c Normal file
Просмотреть файл

@ -0,0 +1,659 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdio.h>
#include <string.h>
#include "amqp_management.h"
#include "link.h"
#include "amqpalloc.h"
#include "message_sender.h"
#include "message_receiver.h"
#include "messaging.h"
#include "amqpvalue_to_string.h"
#include "consolelogger.h"
typedef enum OPERATION_STATE_TAG
{
OPERATION_STATE_NOT_SENT,
OPERATION_STATE_AWAIT_REPLY
} OPERATION_STATE;
typedef struct OPERATION_MESSAGE_INSTANCE_TAG
{
MESSAGE_HANDLE message;
OPERATION_STATE operation_state;
ON_OPERATION_COMPLETE on_operation_complete;
void* callback_context;
unsigned long message_id;
} OPERATION_MESSAGE_INSTANCE;
typedef struct AMQP_MANAGEMENT_INSTANCE_TAG
{
SESSION_HANDLE session;
LINK_HANDLE sender_link;
LINK_HANDLE receiver_link;
MESSAGE_SENDER_HANDLE message_sender;
MESSAGE_RECEIVER_HANDLE message_receiver;
OPERATION_MESSAGE_INSTANCE** operation_messages;
size_t operation_message_count;
unsigned long next_message_id;
ON_AMQP_MANAGEMENT_STATE_CHANGED on_amqp_management_state_changed;
void* callback_context;
AMQP_MANAGEMENT_STATE amqp_management_state;
AMQP_MANAGEMENT_STATE previous_amqp_management_state;
unsigned char sender_connected : 1;
unsigned char receiver_connected : 1;
} AMQP_MANAGEMENT_INSTANCE;
static void amqpmanagement_set_state(AMQP_MANAGEMENT_INSTANCE* amqp_management_instance, AMQP_MANAGEMENT_STATE amqp_management_state)
{
amqp_management_instance->previous_amqp_management_state = amqp_management_instance->amqp_management_state;
amqp_management_instance->amqp_management_state = amqp_management_state;
if (amqp_management_instance->on_amqp_management_state_changed != NULL)
{
amqp_management_instance->on_amqp_management_state_changed(amqp_management_instance->callback_context, amqp_management_instance->amqp_management_state, amqp_management_instance->previous_amqp_management_state);
}
}
static void remove_operation_message_by_index(AMQP_MANAGEMENT_INSTANCE* amqp_management_instance, size_t index)
{
message_destroy(amqp_management_instance->operation_messages[index]->message);
amqpalloc_free(amqp_management_instance->operation_messages[index]);
if (amqp_management_instance->operation_message_count - index > 1)
{
memmove(&amqp_management_instance->operation_messages[index], &amqp_management_instance->operation_messages[index + 1], sizeof(OPERATION_MESSAGE_INSTANCE*));
}
if (amqp_management_instance->operation_message_count == 1)
{
amqpalloc_free(amqp_management_instance->operation_messages);
amqp_management_instance->operation_messages = NULL;
}
else
{
OPERATION_MESSAGE_INSTANCE** new_operation_messages = (OPERATION_MESSAGE_INSTANCE**)amqpalloc_realloc(amqp_management_instance->operation_messages, sizeof(OPERATION_MESSAGE_INSTANCE*) * (amqp_management_instance->operation_message_count - 1));
if (new_operation_messages != NULL)
{
amqp_management_instance->operation_messages = new_operation_messages;
}
}
amqp_management_instance->operation_message_count--;
}
static AMQP_VALUE on_message_received(const void* context, MESSAGE_HANDLE message)
{
AMQP_MANAGEMENT_INSTANCE* amqp_management_instance = (AMQP_MANAGEMENT_INSTANCE*)context;
AMQP_VALUE application_properties;
if (message_get_application_properties(message, &application_properties) != 0)
{
/* error */
}
else
{
PROPERTIES_HANDLE response_properties;
if (message_get_properties(message, &response_properties) != 0)
{
/* error */
}
else
{
AMQP_VALUE key;
AMQP_VALUE value;
AMQP_VALUE map;
AMQP_VALUE correlation_id_value;
if (properties_get_correlation_id(response_properties, &correlation_id_value) != 0)
{
/* error */
}
else
{
map = amqpvalue_get_inplace_described_value(application_properties);
if (map == NULL)
{
/* error */
}
else
{
key = amqpvalue_create_string("status-code");
if (key == NULL)
{
/* error */
}
else
{
value = amqpvalue_get_map_value(map, key);
if (value == NULL)
{
/* error */
}
else
{
int32_t status_code;
if (amqpvalue_get_int(value, &status_code) != 0)
{
/* error */
}
else
{
size_t i = 0;
while (i < amqp_management_instance->operation_message_count)
{
if (amqp_management_instance->operation_messages[i]->operation_state == OPERATION_STATE_AWAIT_REPLY)
{
AMQP_VALUE expected_message_id = amqpvalue_create_ulong(amqp_management_instance->operation_messages[i]->message_id);
OPERATION_RESULT operation_result;
if (expected_message_id == NULL)
{
break;
}
else
{
if (amqpvalue_are_equal(correlation_id_value, expected_message_id))
{
if (status_code != 200)
{
operation_result = OPERATION_RESULT_OPERATION_FAILED;
}
else
{
operation_result = OPERATION_RESULT_OK;
}
amqp_management_instance->operation_messages[i]->on_operation_complete(amqp_management_instance->operation_messages[i]->callback_context, operation_result, 0, NULL);
remove_operation_message_by_index(amqp_management_instance, i);
amqpvalue_destroy(expected_message_id);
break;
}
amqpvalue_destroy(expected_message_id);
}
}
}
}
amqpvalue_destroy(value);
}
amqpvalue_destroy(key);
}
}
}
properties_destroy(response_properties);
}
application_properties_destroy(application_properties);
}
return messaging_delivery_accepted();
}
static int send_operation_messages(AMQP_MANAGEMENT_INSTANCE* amqp_management_instance)
{
int result;
if ((amqp_management_instance->sender_connected != 0) &&
(amqp_management_instance->receiver_connected != 0))
{
size_t i;
for (i = 0; i < amqp_management_instance->operation_message_count; i++)
{
if (amqp_management_instance->operation_messages[i]->operation_state == OPERATION_STATE_NOT_SENT)
{
if (messagesender_send(amqp_management_instance->message_sender, amqp_management_instance->operation_messages[i]->message, NULL, NULL) != 0)
{
/* error */
break;
}
amqp_management_instance->operation_messages[i]->operation_state = OPERATION_STATE_AWAIT_REPLY;
}
}
if (i < amqp_management_instance->operation_message_count)
{
result = __LINE__;
}
else
{
result = 0;
}
}
else
{
result = 0;
}
return result;
}
static void on_message_sender_state_changed(const void* context, MESSAGE_SENDER_STATE new_state, MESSAGE_SENDER_STATE previous_state)
{
AMQP_MANAGEMENT_INSTANCE* amqp_management_instance = (AMQP_MANAGEMENT_INSTANCE*)context;
switch (new_state)
{
default:
break;
case MESSAGE_SENDER_STATE_OPEN:
amqp_management_instance->sender_connected = 1;
(void)send_operation_messages(amqp_management_instance);
break;
case MESSAGE_SENDER_STATE_CLOSING:
case MESSAGE_SENDER_STATE_ERROR:
amqp_management_instance->sender_connected = 0;
amqpmanagement_set_state(amqp_management_instance, AMQP_MANAGEMENT_STATE_ERROR);
break;
}
}
static void on_message_receiver_state_changed(const void* context, MESSAGE_RECEIVER_STATE new_state, MESSAGE_RECEIVER_STATE previous_state)
{
AMQP_MANAGEMENT_INSTANCE* amqp_management_instance = (AMQP_MANAGEMENT_INSTANCE*)context;
switch (new_state)
{
default:
break;
case MESSAGE_RECEIVER_STATE_OPEN:
amqp_management_instance->receiver_connected = 1;
(void)send_operation_messages(amqp_management_instance);
break;
case MESSAGE_RECEIVER_STATE_CLOSING:
case MESSAGE_RECEIVER_STATE_ERROR:
amqp_management_instance->receiver_connected = 0;
amqpmanagement_set_state(amqp_management_instance, AMQP_MANAGEMENT_STATE_ERROR);
break;
}
}
static int set_message_id(MESSAGE_HANDLE message, unsigned long next_message_id)
{
int result = 0;
PROPERTIES_HANDLE properties;
if (message_get_properties(message, &properties) != 0)
{
result = __LINE__;
}
else
{
AMQP_VALUE message_id = amqpvalue_create_message_id_ulong(next_message_id);
if (message_id == NULL)
{
result = __LINE__;
}
else
{
if (properties_set_message_id(properties, message_id) != 0)
{
result = __LINE__;
}
amqpvalue_destroy(message_id);
}
if (message_set_properties(message, properties) != 0)
{
result = __LINE__;
}
properties_destroy(properties);
}
return result;
}
static int add_string_key_value_pair_to_map(AMQP_VALUE map, const char* key, const char* value)
{
int result;
AMQP_VALUE key_value = amqpvalue_create_string(key);
if (key == NULL)
{
result = __LINE__;
}
else
{
AMQP_VALUE value_value = amqpvalue_create_string(value);
if (value_value == NULL)
{
result = __LINE__;
}
else
{
if (amqpvalue_set_map_value(map, key_value, value_value) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
amqpvalue_destroy(key_value);
}
amqpvalue_destroy(value_value);
}
return result;
}
AMQP_MANAGEMENT_HANDLE amqpmanagement_create(SESSION_HANDLE session, const char* management_node, ON_AMQP_MANAGEMENT_STATE_CHANGED on_amqp_management_state_changed, void* callback_context)
{
AMQP_MANAGEMENT_INSTANCE* result;
if (session == NULL)
{
result = NULL;
}
else
{
result = (AMQP_MANAGEMENT_INSTANCE*)amqpalloc_malloc(sizeof(AMQP_MANAGEMENT_INSTANCE));
if (result != NULL)
{
result->session = session;
result->sender_connected = 0;
result->receiver_connected = 0;
result->operation_message_count = 0;
result->operation_messages = NULL;
result->on_amqp_management_state_changed = on_amqp_management_state_changed;
result->callback_context = callback_context;
AMQP_VALUE source = messaging_create_source(management_node);
if (source == NULL)
{
amqpalloc_free(result);
result = NULL;
}
else
{
AMQP_VALUE target = messaging_create_target(management_node);
if (target == NULL)
{
amqpalloc_free(result);
result = NULL;
}
else
{
static const char* sender_suffix = "-sender";
char* sender_link_name = (char*)amqpalloc_malloc(strlen(management_node) + strlen(sender_suffix) + 1);
if (sender_link_name == NULL)
{
result = NULL;
}
else
{
static const char* receiver_suffix = "-receiver";
(void)strcpy(sender_link_name, management_node);
(void)strcat(sender_link_name, sender_suffix);
char* receiver_link_name = (char*)amqpalloc_malloc(strlen(management_node) + strlen(receiver_suffix) + 1);
if (receiver_link_name == NULL)
{
result = NULL;
}
else
{
(void)strcpy(receiver_link_name, management_node);
(void)strcat(receiver_link_name, receiver_suffix);
result->sender_link = link_create(session, "cbs-sender", role_sender, source, target);
if (result->sender_link == NULL)
{
amqpalloc_free(result);
result = NULL;
}
else
{
result->receiver_link = link_create(session, "cbs-receiver", role_receiver, source, target);
if (result->receiver_link == NULL)
{
link_destroy(result->sender_link);
amqpalloc_free(result);
result = NULL;
}
else
{
if ((link_set_max_message_size(result->sender_link, 65535) != 0) ||
(link_set_max_message_size(result->receiver_link, 65535) != 0))
{
link_destroy(result->sender_link);
link_destroy(result->receiver_link);
amqpalloc_free(result);
result = NULL;
}
else
{
result->message_sender = messagesender_create(result->sender_link, on_message_sender_state_changed, result, NULL);
if (result->message_sender == NULL)
{
link_destroy(result->sender_link);
link_destroy(result->receiver_link);
amqpalloc_free(result);
result = NULL;
}
else
{
result->message_receiver = messagereceiver_create(result->receiver_link, on_message_receiver_state_changed, result);
if (result->message_receiver == NULL)
{
messagesender_destroy(result->message_sender);
link_destroy(result->sender_link);
link_destroy(result->receiver_link);
amqpalloc_free(result);
result = NULL;
}
else
{
result->next_message_id = 0;
}
}
}
}
}
amqpalloc_free(receiver_link_name);
}
amqpalloc_free(sender_link_name);
}
amqpvalue_destroy(target);
}
amqpvalue_destroy(source);
}
}
}
return result;
}
void amqpmanagement_destroy(AMQP_MANAGEMENT_HANDLE amqp_management)
{
if (amqp_management != NULL)
{
(void)amqpmanagement_close(amqp_management);
if (amqp_management->operation_message_count > 0)
{
size_t i;
for (i = 0; i < amqp_management->operation_message_count; i++)
{
message_destroy(amqp_management->operation_messages[i]->message);
amqpalloc_free(amqp_management->operation_messages[i]);
}
amqpalloc_free(amqp_management->operation_messages);
}
link_destroy(amqp_management->sender_link);
link_destroy(amqp_management->receiver_link);
messagesender_destroy(amqp_management->message_sender);
messagereceiver_destroy(amqp_management->message_receiver);
amqpalloc_free(amqp_management);
}
}
int amqpmanagement_open(AMQP_MANAGEMENT_HANDLE amqp_management)
{
int result;
if (amqp_management == NULL)
{
result = __LINE__;
}
else
{
if (messagereceiver_open(amqp_management->message_receiver, on_message_received, amqp_management) != 0)
{
result = __LINE__;
}
else
{
if (messagesender_open(amqp_management->message_sender) != 0)
{
messagereceiver_close(amqp_management->message_receiver);
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
int amqpmanagement_close(AMQP_MANAGEMENT_HANDLE amqp_management)
{
int result;
if (amqp_management == NULL)
{
result = __LINE__;
}
else
{
if ((messagesender_close(amqp_management->message_sender) != 0) ||
(messagereceiver_close(amqp_management->message_receiver) != 0))
{
result = __LINE__;
}
else
{
result = 0;
}
}
return result;
}
int amqpmanagement_start_operation(AMQP_MANAGEMENT_HANDLE amqp_management, const char* operation, const char* type, const char* locales, MESSAGE_HANDLE message, ON_OPERATION_COMPLETE on_operation_complete, void* context)
{
int result;
if ((amqp_management == NULL) ||
(operation == NULL))
{
result = __LINE__;
}
else
{
AMQP_VALUE application_properties;
if (message_get_application_properties(message, &application_properties) != 0)
{
result = __LINE__;
}
else
{
if ((add_string_key_value_pair_to_map(application_properties, "operation", operation) != 0) ||
(add_string_key_value_pair_to_map(application_properties, "type", type) != 0) ||
((locales != NULL) && (add_string_key_value_pair_to_map(application_properties, "locales", locales) != 0)))
{
result = __LINE__;
}
else
{
if ((message_set_application_properties(message, application_properties) != 0) ||
(set_message_id(message, amqp_management->next_message_id) != 0))
{
result = __LINE__;
}
else
{
OPERATION_MESSAGE_INSTANCE* pending_operation_message = amqpalloc_malloc(sizeof(OPERATION_MESSAGE_INSTANCE));
if (pending_operation_message == NULL)
{
result = __LINE__;
}
else
{
pending_operation_message->message = message_clone(message);
pending_operation_message->callback_context = context;
pending_operation_message->on_operation_complete = on_operation_complete;
pending_operation_message->operation_state = OPERATION_STATE_NOT_SENT;
pending_operation_message->message_id = amqp_management->next_message_id;
amqp_management->next_message_id++;
OPERATION_MESSAGE_INSTANCE** new_operation_messages = amqpalloc_realloc(amqp_management->operation_messages, (amqp_management->operation_message_count + 1) * sizeof(OPERATION_MESSAGE_INSTANCE*));
if (new_operation_messages == NULL)
{
message_destroy(message);
amqpalloc_free(pending_operation_message);
result = __LINE__;
}
else
{
amqp_management->operation_messages = new_operation_messages;
amqp_management->operation_messages[amqp_management->operation_message_count] = pending_operation_message;
amqp_management->operation_message_count++;
if (send_operation_messages(amqp_management) != 0)
{
if (on_operation_complete != NULL)
{
on_operation_complete(context, OPERATION_RESULT_CBS_ERROR, 0, NULL);
}
result = __LINE__;
}
else
{
result = 0;
}
}
}
}
}
amqpvalue_destroy(application_properties);
}
}
return result;
}

282
src/amqpalloc.c Normal file
Просмотреть файл

@ -0,0 +1,282 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif /* _CRTDBG_MAP_ALLOC */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "amqpalloc.h"
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)~(size_t)0)
#endif
static bool alloc_trace = false;
typedef struct ALLOCATION_TAG
{
size_t size;
void* ptr;
void* next;
} ALLOCATION;
static ALLOCATION* head = NULL;
static size_t total_size = 0;
static size_t max_size = 0;
#define LOG_TRACE_MALLOC // printf
#ifndef DISABLE_MEMORY_TRACE
void* trace_malloc(size_t size)
{
void* result;
ALLOCATION* allocation = (ALLOCATION*)malloc(sizeof(ALLOCATION));
if (allocation == NULL)
{
result = NULL;
}
else
{
LOG_TRACE_MALLOC("Alloc: %lu\r\n", (unsigned long)size);
result = malloc(size);
if (result == NULL)
{
free(allocation);
}
else
{
allocation->ptr = result;
allocation->size = size;
allocation->next = head;
head = allocation;
total_size += size;
if (max_size < total_size)
{
max_size = total_size;
}
}
}
return result;
}
void* trace_calloc(size_t nmemb, size_t size)
{
void* result;
ALLOCATION* allocation = (ALLOCATION*)malloc(sizeof(ALLOCATION));
if (allocation == NULL)
{
result = NULL;
}
else
{
result = calloc(nmemb, size);
if (result == NULL)
{
free(allocation);
}
else
{
allocation->ptr = result;
allocation->size = nmemb * size;
allocation->next = head;
head = allocation;
total_size += allocation->size;
if (max_size < total_size)
{
max_size = total_size;
}
}
}
return result;
}
void* trace_realloc(void* ptr, size_t size)
{
ALLOCATION* curr;
void* result;
ALLOCATION* allocation = NULL;
if (ptr == NULL)
{
LOG_TRACE_MALLOC("Realloc: %lu\r\n", (unsigned long)size);
allocation = (ALLOCATION*)malloc(sizeof(ALLOCATION));
}
else
{
curr = head;
while (curr != NULL)
{
if (curr->ptr == ptr)
{
allocation = curr;
break;
}
else
{
curr = (ALLOCATION*)curr->next;
}
}
}
if (allocation == NULL)
{
result = NULL;
}
else
{
result = realloc(ptr, size);
if (result == NULL)
{
if (ptr == NULL)
{
free(allocation);
}
}
else
{
if (ptr != NULL)
{
LOG_TRACE_MALLOC("Realloc change: %ld\r\n", (long)size - allocation->size);
allocation->ptr = result;
total_size -= allocation->size;
allocation->size = size;
}
else
{
LOG_TRACE_MALLOC("Realloc: %lu\r\n", (unsigned long)size);
/* add block */
allocation->ptr = result;
allocation->size = size;
allocation->next = head;
head = allocation;
}
total_size += size;
if (max_size < total_size)
{
max_size = total_size;
}
}
}
return result;
}
void trace_free(void* ptr)
{
ALLOCATION* curr = head;
ALLOCATION* prev = NULL;
while (curr != NULL)
{
if (curr->ptr == ptr)
{
free(ptr);
LOG_TRACE_MALLOC("Free: %lu\r\n", (unsigned long)curr->size);
total_size -= curr->size;
if (prev != NULL)
{
prev->next = curr->next;
}
else
{
head = (ALLOCATION*)curr->next;
}
free(curr);
break;
}
prev = curr;
curr = (ALLOCATION*)curr->next;
}
}
void* amqpalloc_malloc(size_t size)
{
void* result;
if (!alloc_trace)
{
result = malloc(size);
}
else
{
result = trace_malloc(size);
}
return result;
}
void amqpalloc_free(void* ptr)
{
if (!alloc_trace)
{
free(ptr);
}
else
{
trace_free(ptr);
}
}
void* amqpalloc_calloc(size_t nmemb, size_t size)
{
void* result;
if (!alloc_trace)
{
result = calloc(nmemb, size);
}
else
{
result = trace_calloc(nmemb, size);
}
return result;
}
void* amqpalloc_realloc(void* ptr, size_t size)
{
void* result;
if (!alloc_trace)
{
result = realloc(ptr, size);
}
else
{
result = trace_realloc(ptr, size);
}
return result;
}
#endif
size_t amqpalloc_get_maximum_memory_used(void)
{
return max_size;
}
size_t amqpalloc_get_current_memory_used(void)
{
return total_size;
}
void amqpalloc_set_memory_tracing_enabled(bool memory_tracing_enabled)
{
alloc_trace = memory_tracing_enabled;
}

5535
src/amqpvalue.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

671
src/amqpvalue_to_string.c Normal file
Просмотреть файл

@ -0,0 +1,671 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "amqpvalue_to_string.h"
#include "amqpvalue.h"
#include "amqpalloc.h"
#if _WIN32
/* The MS runtime does not have snprintf */
#define snprintf _snprintf
#endif
static int string_concat(char** string, const char* to_concat)
{
int result;
if ((string == NULL) ||
(to_concat == NULL))
{
result = __LINE__;
}
else
{
size_t length = strlen(to_concat) + 1;
size_t src_length;
if (*string != NULL)
{
src_length = strlen(*string);
}
else
{
src_length = 0;
}
length += src_length;
char* new_string = amqpalloc_realloc(*string, length);
if (new_string == NULL)
{
result = __LINE__;
}
else
{
*string = new_string;
(void)strcpy(*string + src_length, to_concat);
result = 0;
}
}
return result;
}
char* amqpvalue_to_string(AMQP_VALUE amqp_value)
{
char* result = NULL;
if (amqp_value != NULL)
{
AMQP_TYPE amqp_type = amqpvalue_get_type(amqp_value);
switch (amqp_type)
{
default:
result = NULL;
break;
case AMQP_TYPE_NULL:
if (string_concat(&result, "NULL") != 0)
{
amqpalloc_free(result);
result = NULL;
}
break;
case AMQP_TYPE_BOOL:
{
bool value;
if ((amqpvalue_get_boolean(amqp_value, &value) != 0) ||
(string_concat(&result, (value == true) ? "true" : "false") != 0))
{
amqpalloc_free(result);
result = NULL;
}
break;
}
case AMQP_TYPE_UBYTE:
{
char str_value[4];
uint8_t value;
if (amqpvalue_get_ubyte(amqp_value, &value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
unsigned int uint_value = value;
if ((sprintf(str_value, "%u", uint_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_USHORT:
{
char str_value[6];
uint16_t value;
if (amqpvalue_get_ushort(amqp_value, &value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
unsigned int uint_value = value;
if ((sprintf(str_value, "%u", uint_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_UINT:
{
char str_value[11];
uint32_t value;
if (amqpvalue_get_uint(amqp_value, &value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
unsigned long uint_value = value;
if ((sprintf(str_value, "%lu", uint_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_ULONG:
{
char str_value[21];
uint64_t value;
if (amqpvalue_get_ulong(amqp_value, &value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
unsigned long long uint_value = value;
if ((sprintf(str_value, "%llu", uint_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_BYTE:
{
char str_value[5];
int8_t value;
if (amqpvalue_get_ubyte(amqp_value, &value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
int int_value = value;
if ((sprintf(str_value, "%d", int_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_SHORT:
{
char str_value[7];
int16_t value;
if (amqpvalue_get_ushort(amqp_value, &value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
int int_value = value;
if ((sprintf(str_value, "%d", int_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_INT:
{
char str_value[12];
int32_t value;
if (amqpvalue_get_int(amqp_value, &value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
unsigned long int_value = value;
if ((sprintf(str_value, "%ld", int_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_LONG:
{
char str_value[21];
int64_t value;
if (amqpvalue_get_ulong(amqp_value, &value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
long long int_value = value;
if ((sprintf(str_value, "%lld", int_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_FLOAT:
{
float float_value;
if (amqpvalue_get_float(amqp_value, &float_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
char str_value[25];
if ((snprintf(str_value, sizeof(str_value), "%.02f", float_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
if (string_concat(&result, str_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_DOUBLE:
{
double double_value;
if (amqpvalue_get_double(amqp_value, &double_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
char str_value[25];
if ((snprintf(str_value, sizeof(str_value), "%.02lf", double_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
if (string_concat(&result, str_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_CHAR:
{
uint32_t char_code;
if (amqpvalue_get_char(amqp_value, &char_code) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
char str_value[25];
if ((snprintf(str_value, sizeof(str_value), "U%02X%02X%02X%02X", char_code >> 24, (char_code >> 16) & 0xFF, (char_code >> 8) & 0xFF, char_code & 0xFF) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
if (string_concat(&result, str_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_TIMESTAMP:
{
char str_value[21];
int64_t value;
if (amqpvalue_get_timestamp(amqp_value, &value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
long long int_value = value;
if ((sprintf(str_value, "%lld", int_value) < 0) ||
(string_concat(&result, str_value) != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_UUID:
break;
case AMQP_TYPE_BINARY:
{
amqp_binary binary_value;
if (amqpvalue_get_binary(amqp_value, &binary_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
if (string_concat(&result, "<") != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
uint64_t i;
for (i = 0; i < binary_value.length; i++)
{
char str_value[4];
if ((snprintf(str_value, sizeof(str_value), "%s%02X", (i > 0) ? " " : "", ((unsigned char*)binary_value.bytes)[i]) < 0) ||
(string_concat(&result, str_value) != 0))
{
break;
}
}
if (i < binary_value.length)
{
amqpalloc_free(result);
result = NULL;
}
else if (string_concat(&result, ">") != 0)
{
amqpalloc_free(result);
result = NULL;
}
}
}
break;
}
case AMQP_TYPE_STRING:
{
const char* string_value;
if (amqpvalue_get_string(amqp_value, &string_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
if (string_concat(&result, string_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_SYMBOL:
{
const char* string_value;
if (amqpvalue_get_symbol(amqp_value, &string_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
if (string_concat(&result, string_value) != 0)
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_LIST:
{
uint32_t count;
if ((amqpvalue_get_list_item_count(amqp_value, &count) != 0) ||
(string_concat(&result, "{") != 0))
{
amqpalloc_free(result);
result = NULL;
}
else
{
size_t i;
for (i = 0; i < count; i++)
{
AMQP_VALUE item = amqpvalue_get_list_item(amqp_value, i);
if (item == NULL)
{
break;
}
else
{
char* item_string = amqpvalue_to_string(item);
if (item_string == NULL)
{
amqpvalue_destroy(item);
break;
}
else
{
if ((i > 0) && (string_concat(&result, ",") != 0))
{
amqpalloc_free(result);
result = NULL;
break;
}
else if (string_concat(&result, item_string) != 0)
{
amqpalloc_free(result);
result = NULL;
break;
}
amqpalloc_free(item_string);
}
amqpvalue_destroy(item);
}
}
if ((i < count) ||
(string_concat(&result, "}") != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_MAP:
{
uint32_t count;
if ((amqpvalue_get_map_pair_count(amqp_value, &count) != 0) ||
(string_concat(&result, "{") != 0))
{
amqpalloc_free(result);
result = NULL;
}
else
{
size_t i;
for (i = 0; i < count; i++)
{
AMQP_VALUE key;
AMQP_VALUE value;
if (amqpvalue_get_map_key_value_pair(amqp_value, i, &key, &value) != 0)
{
break;
}
else
{
char* key_string = amqpvalue_to_string(key);
if (key_string == NULL)
{
amqpvalue_destroy(key);
amqpvalue_destroy(value);
break;
}
else
{
char* value_string = amqpvalue_to_string(value);
if (key_string == NULL)
{
amqpalloc_free(key_string);
amqpvalue_destroy(key);
amqpvalue_destroy(value);
break;
}
else
{
if (((i > 0) && (string_concat(&result, ",") != 0)) ||
(string_concat(&result, "[") != 0) ||
(string_concat(&result, key_string) != 0) ||
(string_concat(&result, ":") != 0) ||
(string_concat(&result, value_string) != 0) ||
(string_concat(&result, "]") != 0))
{
amqpalloc_free(key_string);
amqpalloc_free(value_string);
amqpvalue_destroy(key);
amqpvalue_destroy(value);
break;
}
amqpalloc_free(value_string);
}
amqpalloc_free(key_string);
}
amqpvalue_destroy(key);
amqpvalue_destroy(value);
}
}
if ((i < count) ||
(string_concat(&result, "}") != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_ARRAY:
{
uint32_t count;
if ((amqpvalue_get_array_item_count(amqp_value, &count) != 0) ||
(string_concat(&result, "{") != 0))
{
amqpalloc_free(result);
result = NULL;
}
else
{
size_t i;
for (i = 0; i < count; i++)
{
AMQP_VALUE item = amqpvalue_get_array_item(amqp_value, i);
if (item == NULL)
{
break;
}
else
{
char* item_string = amqpvalue_to_string(item);
if (item_string == NULL)
{
amqpvalue_destroy(item);
break;
}
else
{
if ((i > 0) && (string_concat(&result, ",") != 0))
{
amqpalloc_free(result);
result = NULL;
break;
}
else if (string_concat(&result, item_string) != 0)
{
amqpalloc_free(result);
result = NULL;
break;
}
amqpalloc_free(item_string);
}
amqpvalue_destroy(item);
}
}
if ((i < count) ||
(string_concat(&result, "}") != 0))
{
amqpalloc_free(result);
result = NULL;
}
}
break;
}
case AMQP_TYPE_COMPOSITE:
case AMQP_TYPE_DESCRIBED:
{
AMQP_VALUE described_value = amqpvalue_get_inplace_described_value(amqp_value);
if (described_value == NULL)
{
amqpalloc_free(result);
result = NULL;
}
else
{
if (string_concat(&result, "* ") != 0)
{
amqpalloc_free(result);
result = NULL;
}
else
{
char* described_value_string = amqpvalue_to_string(described_value);
if (described_value_string == NULL)
{
amqpalloc_free(result);
result = NULL;
}
else
{
if (string_concat(&result, described_value_string) != 0)
{
amqpalloc_free(result);
result = NULL;
}
amqpalloc_free(described_value_string);
}
}
}
break;
}
}
}
return result;
}

336
src/cbs.c Normal file
Просмотреть файл

@ -0,0 +1,336 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdio.h>
#include <string.h>
#include "cbs.h"
#include "amqp_management.h"
#include "amqpalloc.h"
#include "session.h"
#include "consolelogger.h"
typedef struct CBS_INSTANCE_TAG
{
AMQP_MANAGEMENT_HANDLE amqp_management;
} CBS_INSTANCE;
static int add_string_key_value_pair_to_map(AMQP_VALUE map, const char* key, const char* value)
{
int result;
AMQP_VALUE key_value = amqpvalue_create_string(key);
if (key == NULL)
{
result = __LINE__;
}
else
{
AMQP_VALUE value_value = amqpvalue_create_string(value);
if (value_value == NULL)
{
result = __LINE__;
}
else
{
if (amqpvalue_set_map_value(map, key_value, value_value) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
amqpvalue_destroy(key_value);
}
amqpvalue_destroy(value_value);
}
return result;
}
static int set_pending_operation_properties(MESSAGE_HANDLE message)
{
int result = 0;
PROPERTIES_HANDLE properties = properties_create();
if (properties == NULL)
{
result = __LINE__;
}
else
{
AMQP_VALUE reply_to = amqpvalue_create_address_string("cbs");
if (reply_to == NULL)
{
result = __LINE__;
}
else
{
if (properties_set_reply_to(properties, reply_to) != 0)
{
result = __LINE__;
}
amqpvalue_destroy(reply_to);
}
AMQP_VALUE message_id = amqpvalue_create_message_id_ulong(0x43);
if (message_id == NULL)
{
result = __LINE__;
}
else
{
if (properties_set_message_id(properties, message_id) != 0)
{
result = __LINE__;
}
amqpvalue_destroy(message_id);
}
if (message_set_properties(message, properties) != 0)
{
result = __LINE__;
}
properties_destroy(properties);
}
return result;
}
CBS_HANDLE cbs_create(SESSION_HANDLE session, ON_AMQP_MANAGEMENT_STATE_CHANGED on_amqp_management_state_changed, void* callback_context)
{
CBS_INSTANCE* result;
if (session == NULL)
{
result = NULL;
}
else
{
result = (CBS_INSTANCE*)amqpalloc_malloc(sizeof(CBS_INSTANCE));
if (result != NULL)
{
result->amqp_management = amqpmanagement_create(session, "$cbs", on_amqp_management_state_changed, callback_context);
if (result->amqp_management == NULL)
{
amqpalloc_free(result);
result = NULL;
}
}
}
return result;
}
void cbs_destroy(CBS_HANDLE cbs)
{
if (cbs != NULL)
{
(void)cbs_close(cbs);
amqpmanagement_destroy(cbs->amqp_management);
amqpalloc_free(cbs);
}
}
int cbs_open(CBS_HANDLE cbs)
{
int result;
if (cbs == NULL)
{
result = __LINE__;
}
else
{
if (amqpmanagement_open(cbs->amqp_management) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
return result;
}
int cbs_close(CBS_HANDLE cbs)
{
int result;
if (cbs == NULL)
{
result = __LINE__;
}
else
{
if (amqpmanagement_close(cbs->amqp_management) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
return result;
}
int cbs_put_token(CBS_HANDLE cbs, const char* type, const char* audience, const char* token, ON_CBS_OPERATION_COMPLETE on_operation_complete, void* context)
{
int result;
if ((cbs == NULL) ||
(token == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_HANDLE message = message_create();
if (message == NULL)
{
result = __LINE__;
}
else
{
AMQP_VALUE token_value = amqpvalue_create_string(token);
if (token_value == NULL)
{
message_destroy(message);
result = __LINE__;
}
else
{
if (message_set_body_amqp_value(message, token_value) != 0)
{
result = __LINE__;
}
else
{
AMQP_VALUE application_properties = amqpvalue_create_map();
if (application_properties == NULL)
{
result = __LINE__;
}
else
{
if (add_string_key_value_pair_to_map(application_properties, "name", audience) != 0)
{
result = __LINE__;
}
else
{
if (message_set_application_properties(message, application_properties) != 0)
{
result = __LINE__;
}
else
{
if (set_pending_operation_properties(message) != 0)
{
result = __LINE__;
}
else
{
if (amqpmanagement_start_operation(cbs->amqp_management, "put-token", type, NULL, message, (ON_OPERATION_COMPLETE)on_operation_complete, context) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
}
amqpvalue_destroy(application_properties);
}
amqpvalue_destroy(token_value);
}
}
message_destroy(message);
}
}
return result;
}
int cbs_delete_token(CBS_HANDLE cbs, const char* type, const char* audience, ON_CBS_OPERATION_COMPLETE on_operation_complete, void* context)
{
int result;
if (cbs == NULL)
{
result = __LINE__;
}
else
{
MESSAGE_HANDLE message = message_create();
if (message == NULL)
{
result = __LINE__;
}
else
{
AMQP_VALUE application_properties = amqpvalue_create_map();
if (application_properties == NULL)
{
result = __LINE__;
}
else
{
if (add_string_key_value_pair_to_map(application_properties, "name", audience) != 0)
{
result = __LINE__;
}
else
{
if (message_set_application_properties(message, application_properties) != 0)
{
result = __LINE__;
}
else
{
if (set_pending_operation_properties(message) != 0)
{
result = __LINE__;
}
else
{
if (amqpmanagement_start_operation(cbs->amqp_management, "delete-token", type, NULL, message, (ON_OPERATION_COMPLETE)on_operation_complete, context) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
}
amqpvalue_destroy(application_properties);
}
message_destroy(message);
}
}
return result;
}

1542
src/connection.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

23
src/consolelogger.c Normal file
Просмотреть файл

@ -0,0 +1,23 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include "logger.h"
void consolelogger_log(unsigned int options, char* format, ...)
{
va_list args;
va_start(args, format);
(void)vprintf(format, args);
va_end(args);
if (options & LOG_LINE)
{
(void)printf("\r\n");
}
}

630
src/frame_codec.c Normal file
Просмотреть файл

@ -0,0 +1,630 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "frame_codec.h"
#include "amqpvalue.h"
#include "logger.h"
#include "xio.h"
#include "amqpalloc.h"
#include "list.h"
#define FRAME_HEADER_SIZE 8
#define MAX_TYPE_SPECIFIC_SIZE ((255 * 4) - 6)
typedef enum RECEIVE_FRAME_STATE_TAG
{
RECEIVE_FRAME_STATE_FRAME_SIZE,
RECEIVE_FRAME_STATE_DOFF,
RECEIVE_FRAME_STATE_FRAME_TYPE,
RECEIVE_FRAME_STATE_TYPE_SPECIFIC,
RECEIVE_FRAME_STATE_FRAME_BODY,
RECEIVE_FRAME_STATE_ERROR
} RECEIVE_FRAME_STATE;
typedef enum ENCODE_FRAME_STATE_TAG
{
ENCODE_FRAME_STATE_IDLE,
ENCODE_FRAME_STATE_ERROR
} ENCODE_FRAME_STATE;
typedef struct SUBSCRIPTION_TAG
{
uint8_t frame_type;
ON_FRAME_RECEIVED on_frame_received;
void* callback_context;
} SUBSCRIPTION;
typedef struct FRAME_CODEC_INSTANCE_TAG
{
LOGGER_LOG logger_log;
/* subscriptions */
LIST_HANDLE subscription_list;
/* decode frame */
RECEIVE_FRAME_STATE receive_frame_state;
size_t receive_frame_pos;
uint32_t receive_frame_size;
uint32_t type_specific_size;
uint8_t receive_frame_doff;
uint8_t receive_frame_type;
SUBSCRIPTION* receive_frame_subscription;
unsigned char* receive_frame_bytes;
ON_FRAME_CODEC_ERROR on_frame_codec_error;
void* on_frame_codec_error_callback_context;
/* encode frame */
ENCODE_FRAME_STATE encode_frame_state;
/* configuration */
uint32_t max_frame_size;
} FRAME_CODEC_INSTANCE;
static bool find_subscription_by_frame_type(LIST_ITEM_HANDLE list_item, const void* match_context)
{
bool result;
SUBSCRIPTION* subscription = (SUBSCRIPTION*)list_item_get_value(list_item);
if (subscription == NULL)
{
result = false;
}
else
{
result = subscription->frame_type == *((uint8_t*)match_context) ? true : false;
}
return result;
}
FRAME_CODEC_HANDLE frame_codec_create(ON_FRAME_CODEC_ERROR on_frame_codec_error, void* callback_context, LOGGER_LOG logger_log)
{
FRAME_CODEC_INSTANCE* result;
/* Codes_SRS_FRAME_CODEC_01_020: [If the on_frame_codec_error argument is NULL, frame_codec_create shall return NULL.] */
/* Codes_SRS_FRAME_CODEC_01_104: [The callback_context shall be allowed to be NULL.] */
if (on_frame_codec_error == NULL)
{
result = NULL;
}
else
{
result = amqpalloc_malloc(sizeof(FRAME_CODEC_INSTANCE));
/* Codes_SRS_FRAME_CODEC_01_022: [If allocating memory for the frame_codec instance fails, frame_codec_create shall return NULL.] */
if (result != NULL)
{
/* Codes_SRS_FRAME_CODEC_01_021: [frame_codec_create shall create a new instance of frame_codec and return a non-NULL handle to it on success.] */
result->logger_log = logger_log;
result->encode_frame_state = ENCODE_FRAME_STATE_IDLE;
result->receive_frame_state = RECEIVE_FRAME_STATE_FRAME_SIZE;
result->on_frame_codec_error = on_frame_codec_error;
result->on_frame_codec_error_callback_context = callback_context;
result->receive_frame_pos = 0;
result->receive_frame_size = 0;
result->receive_frame_bytes = NULL;
result->subscription_list = list_create();
/* Codes_SRS_FRAME_CODEC_01_082: [The initial max_frame_size_shall be 512.] */
result->max_frame_size = 512;
}
}
return result;
}
void frame_codec_destroy(FRAME_CODEC_HANDLE frame_codec)
{
/* Codes_SRS_FRAME_CODEC_01_024: [If frame_codec is NULL, frame_codec_destroy shall do nothing.] */
if (frame_codec != NULL)
{
FRAME_CODEC_INSTANCE* frame_codec_data = (FRAME_CODEC_INSTANCE*)frame_codec;
list_destroy(frame_codec_data->subscription_list);
if (frame_codec_data->receive_frame_bytes != NULL)
{
amqpalloc_free(frame_codec_data->receive_frame_bytes);
}
/* Codes_SRS_FRAME_CODEC_01_023: [frame_codec_destroy shall free all resources associated with a frame_codec instance.] */
amqpalloc_free(frame_codec);
}
}
int frame_codec_set_max_frame_size(FRAME_CODEC_HANDLE frame_codec, uint32_t max_frame_size)
{
int result;
FRAME_CODEC_INSTANCE* frame_codec_data = (FRAME_CODEC_INSTANCE*)frame_codec;
/* Codes_SRS_FRAME_CODEC_01_077: [If frame_codec is NULL, frame_codec_set_max_frame_size shall return a non-zero value.] */
if ((frame_codec == NULL) ||
/* Codes_SRS_FRAME_CODEC_01_078: [If max_frame_size is invalid according to the AMQP standard, frame_codec_set_max_frame_size shall return a non-zero value.] */
(max_frame_size < FRAME_HEADER_SIZE) ||
/* Codes_SRS_FRAME_CODEC_01_081: [If a frame being decoded already has a size bigger than the max_frame_size argument then frame_codec_set_max_frame_size shall return a non-zero value and the previous frame size shall be kept.] */
((max_frame_size < frame_codec_data->receive_frame_size) && (frame_codec_data->receive_frame_state != RECEIVE_FRAME_STATE_FRAME_SIZE)) ||
/* Codes_SRS_FRAME_CODEC_01_097: [Setting a frame size on a frame_codec that had a decode error shall fail.] */
(frame_codec_data->receive_frame_state == RECEIVE_FRAME_STATE_ERROR) ||
/* Codes_SRS_FRAME_CODEC_01_098: [Setting a frame size on a frame_codec that had an encode error shall fail.] */
(frame_codec_data->encode_frame_state == ENCODE_FRAME_STATE_ERROR))
{
result = __LINE__;
}
else
{
/* Codes_SRS_FRAME_CODEC_01_075: [frame_codec_set_max_frame_size shall set the maximum frame size for a frame_codec.] */
/* Codes_SRS_FRAME_CODEC_01_079: [The new frame size shall take effect immediately, even for a frame that is being decoded at the time of the call.] */
frame_codec_data->max_frame_size = max_frame_size;
/* Codes_SRS_FRAME_CODEC_01_076: [On success, frame_codec_set_max_frame_size shall return 0.] */
result = 0;
}
return result;
}
/* Codes_SRS_FRAME_CODEC_01_001: [Frames are divided into three distinct areas: a fixed width frame header, a variable width extended header, and a variable width frame body.] */
/* Codes_SRS_FRAME_CODEC_01_002: [frame header The frame header is a fixed size (8 byte) structure that precedes each frame.] */
/* Codes_SRS_FRAME_CODEC_01_003: [The frame header includes mandatory information necessary to parse the rest of the frame including size and type information.] */
/* Codes_SRS_FRAME_CODEC_01_004: [extended header The extended header is a variable width area preceding the frame body.] */
/* Codes_SRS_FRAME_CODEC_01_007: [frame body The frame body is a variable width sequence of bytes the format of which depends on the frame type.] */
/* Codes_SRS_FRAME_CODEC_01_028: [The sequence of bytes shall be decoded according to the AMQP ISO.] */
/* Codes_SRS_FRAME_CODEC_01_029: [The sequence of bytes does not have to be a complete frame, frame_codec shall be responsible for maintaining decoding state between frame_codec_receive_bytes calls.] */
int frame_codec_receive_bytes(FRAME_CODEC_HANDLE frame_codec, const unsigned char* buffer, size_t size)
{
int result;
FRAME_CODEC_INSTANCE* frame_codec_data = (FRAME_CODEC_INSTANCE*)frame_codec;
/* Codes_SRS_FRAME_CODEC_01_026: [If frame_codec or buffer are NULL, frame_codec_receive_bytes shall return a non-zero value.] */
if ((frame_codec == NULL) ||
(buffer == NULL) ||
/* Codes_SRS_FRAME_CODEC_01_027: [If size is zero, frame_codec_receive_bytes shall return a non-zero value.] */
(size == 0))
{
result = __LINE__;
}
else
{
while (size > 0)
{
switch (frame_codec_data->receive_frame_state)
{
default:
case RECEIVE_FRAME_STATE_ERROR:
/* Codes_SRS_FRAME_CODEC_01_074: [If a decoding error is detected, any subsequent calls on frame_codec_data_receive_bytes shall fail.] */
result = __LINE__;
size = 0;
break;
/* Codes_SRS_FRAME_CODEC_01_008: [SIZE Bytes 0-3 of the frame header contain the frame size.] */
case RECEIVE_FRAME_STATE_FRAME_SIZE:
/* Codes_SRS_FRAME_CODEC_01_009: [This is an unsigned 32-bit integer that MUST contain the total frame size of the frame header, extended header, and frame body.] */
frame_codec_data->receive_frame_size += buffer[0] << (24 - frame_codec_data->receive_frame_pos * 8);
buffer++;
size--;
frame_codec_data->receive_frame_pos++;
if (frame_codec_data->receive_frame_pos == 4)
{
/* Codes_SRS_FRAME_CODEC_01_010: [The frame is malformed if the size is less than the size of the frame header (8 bytes).] */
if ((frame_codec_data->receive_frame_size < FRAME_HEADER_SIZE) ||
/* Codes_SRS_FRAME_CODEC_01_096: [If a frame bigger than the current max frame size is received, frame_codec_receive_bytes shall fail and return a non-zero value.] */
(frame_codec_data->receive_frame_size > frame_codec_data->max_frame_size))
{
/* Codes_SRS_FRAME_CODEC_01_074: [If a decoding error is detected, any subsequent calls on frame_codec_data_receive_bytes shall fail.] */
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_ERROR;
/* Codes_SRS_FRAME_CODEC_01_103: [Upon any decode error, if an error callback has been passed to frame_codec_create, then the error callback shall be called with the context argument being the on_frame_codec_error_callback_context argument passed to frame_codec_create.] */
frame_codec_data->on_frame_codec_error(frame_codec_data->on_frame_codec_error_callback_context);
result = __LINE__;
}
else
{
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_DOFF;
result = 0;
}
}
else
{
result = 0;
}
break;
case RECEIVE_FRAME_STATE_DOFF:
/* Codes_SRS_FRAME_CODEC_01_011: [DOFF Byte 4 of the frame header is the data offset.] */
/* Codes_SRS_FRAME_CODEC_01_013: [The value of the data offset is an unsigned, 8-bit integer specifying a count of 4-byte words.] */
/* Codes_SRS_FRAME_CODEC_01_012: [This gives the position of the body within the frame.] */
frame_codec_data->receive_frame_doff = buffer[0];
buffer++;
size--;
/* Codes_SRS_FRAME_CODEC_01_014: [Due to the mandatory 8-byte frame header, the frame is malformed if the value is less than 2.] */
if (frame_codec_data->receive_frame_doff < 2)
{
/* Codes_SRS_FRAME_CODEC_01_074: [If a decoding error is detected, any subsequent calls on frame_codec_data_receive_bytes shall fail.] */
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_ERROR;
/* Codes_SRS_FRAME_CODEC_01_103: [Upon any decode error, if an error callback has been passed to frame_codec_create, then the error callback shall be called with the context argument being the on_frame_codec_error_callback_context argument passed to frame_codec_create.] */
frame_codec_data->on_frame_codec_error(frame_codec_data->on_frame_codec_error_callback_context);
result = __LINE__;
}
else
{
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_FRAME_TYPE;
result = 0;
}
break;
case RECEIVE_FRAME_STATE_FRAME_TYPE:
{
LIST_ITEM_HANDLE item_handle;
frame_codec_data->type_specific_size = (frame_codec_data->receive_frame_doff * 4) - 6;
/* Codes_SRS_FRAME_CODEC_01_015: [TYPE Byte 5 of the frame header is a type code.] */
frame_codec_data->receive_frame_type = buffer[0];
buffer++;
size--;
/* Codes_SRS_FRAME_CODEC_01_035: [After successfully registering a callback for a certain frame type, when subsequently that frame type is received the callbacks shall be invoked, passing to it the received frame and the callback_context value.] */
item_handle = list_find(frame_codec_data->subscription_list, find_subscription_by_frame_type, &frame_codec_data->receive_frame_type);
if (item_handle == NULL)
{
frame_codec_data->receive_frame_subscription = NULL;
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_TYPE_SPECIFIC;
result = 0;
break;
}
else
{
frame_codec_data->receive_frame_subscription = (SUBSCRIPTION*)list_item_get_value(item_handle);
if (frame_codec_data->receive_frame_subscription == NULL)
{
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_TYPE_SPECIFIC;
result = 0;
break;
}
else
{
frame_codec_data->receive_frame_pos = 0;
/* Codes_SRS_FRAME_CODEC_01_102: [frame_codec_receive_bytes shall allocate memory to hold the frame_body bytes.] */
frame_codec_data->receive_frame_bytes = (unsigned char*)amqpalloc_malloc(frame_codec_data->receive_frame_size - 6);
if (frame_codec_data->receive_frame_bytes == NULL)
{
/* Codes_SRS_FRAME_CODEC_01_101: [If the memory for the frame_body bytes cannot be allocated, frame_codec_receive_bytes shall fail and return a non-zero value.] */
/* Codes_SRS_FRAME_CODEC_01_030: [If a decoding error occurs, frame_codec_data_receive_bytes shall return a non-zero value.] */
/* Codes_SRS_FRAME_CODEC_01_074: [If a decoding error is detected, any subsequent calls on frame_codec_data_receive_bytes shall fail.] */
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_ERROR;
/* Codes_SRS_FRAME_CODEC_01_103: [Upon any decode error, if an error callback has been passed to frame_codec_create, then the error callback shall be called with the context argument being the on_frame_codec_error_callback_context argument passed to frame_codec_create.] */
frame_codec_data->on_frame_codec_error(frame_codec_data->on_frame_codec_error_callback_context);
result = __LINE__;
break;
}
else
{
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_TYPE_SPECIFIC;
result = 0;
break;
}
}
}
}
case RECEIVE_FRAME_STATE_TYPE_SPECIFIC:
{
uint32_t to_copy = frame_codec_data->type_specific_size - frame_codec_data->receive_frame_pos;
if (to_copy > size)
{
to_copy = size;
}
if (frame_codec_data->receive_frame_subscription != NULL)
{
(void)memcpy(&frame_codec_data->receive_frame_bytes[frame_codec_data->receive_frame_pos], buffer, to_copy);
frame_codec_data->receive_frame_pos += to_copy;
buffer += to_copy;
size -= to_copy;
}
else
{
frame_codec_data->receive_frame_pos += to_copy;
buffer += to_copy;
size -= to_copy;
}
if (frame_codec_data->receive_frame_pos == frame_codec_data->type_specific_size)
{
if (frame_codec_data->receive_frame_size == FRAME_HEADER_SIZE)
{
if (frame_codec_data->receive_frame_subscription != NULL)
{
/* Codes_SRS_FRAME_CODEC_01_031: [When a complete frame is successfully decoded it shall be indicated to the upper layer by invoking the on_frame_received passed to frame_codec_subscribe.] */
/* Codes_SRS_FRAME_CODEC_01_032: [Besides passing the frame information, the callback_context value passed to frame_codec_data_subscribe shall be passed to the on_frame_received function.] */
/* Codes_SRS_FRAME_CODEC_01_005: [This is an extension point defined for future expansion.] */
/* Codes_SRS_FRAME_CODEC_01_006: [The treatment of this area depends on the frame type.] */
/* Codes_SRS_FRAME_CODEC_01_100: [If the frame body size is 0, the frame_body pointer passed to on_frame_received shall be NULL.] */
frame_codec_data->receive_frame_subscription->on_frame_received(frame_codec_data->receive_frame_subscription->callback_context, frame_codec_data->receive_frame_bytes, frame_codec_data->type_specific_size, NULL, 0);
amqpalloc_free(frame_codec_data->receive_frame_bytes);
frame_codec_data->receive_frame_bytes = NULL;
}
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_FRAME_SIZE;
frame_codec_data->receive_frame_size = 0;
}
else
{
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_FRAME_BODY;
}
frame_codec_data->receive_frame_pos = 0;
}
result = 0;
break;
}
case RECEIVE_FRAME_STATE_FRAME_BODY:
{
uint32_t frame_body_size = frame_codec_data->receive_frame_size - (frame_codec_data->receive_frame_doff * 4);
uint32_t to_copy = frame_body_size - frame_codec_data->receive_frame_pos;
if (to_copy > size)
{
to_copy = size;
}
(void)memcpy(frame_codec_data->receive_frame_bytes + frame_codec_data->receive_frame_pos + frame_codec_data->type_specific_size, buffer, to_copy);
buffer += to_copy;
size -= to_copy;
frame_codec_data->receive_frame_pos += to_copy;
if (frame_codec_data->receive_frame_pos == frame_body_size)
{
if (frame_codec_data->receive_frame_subscription != NULL)
{
/* Codes_SRS_FRAME_CODEC_01_031: [When a complete frame is successfully decoded it shall be indicated to the upper layer by invoking the on_frame_received passed to frame_codec_subscribe.] */
/* Codes_SRS_FRAME_CODEC_01_032: [Besides passing the frame information, the callback_context value passed to frame_codec_data_subscribe shall be passed to the on_frame_received function.] */
/* Codes_SRS_FRAME_CODEC_01_005: [This is an extension point defined for future expansion.] */
/* Codes_SRS_FRAME_CODEC_01_006: [The treatment of this area depends on the frame type.] */
/* Codes_SRS_FRAME_CODEC_01_099: [A pointer to the frame_body bytes shall also be passed to the on_frame_received.] */
frame_codec_data->receive_frame_subscription->on_frame_received(frame_codec_data->receive_frame_subscription->callback_context, frame_codec_data->receive_frame_bytes, frame_codec_data->type_specific_size, frame_codec_data->receive_frame_bytes + frame_codec_data->type_specific_size, frame_body_size);
amqpalloc_free(frame_codec_data->receive_frame_bytes);
frame_codec_data->receive_frame_bytes = NULL;
}
frame_codec_data->receive_frame_state = RECEIVE_FRAME_STATE_FRAME_SIZE;
frame_codec_data->receive_frame_pos = 0;
frame_codec_data->receive_frame_size = 0;
}
result = 0;
break;
}
}
}
}
return result;
}
/* Codes_SRS_FRAME_CODEC_01_033: [frame_codec_subscribe subscribes for a certain type of frame received by the frame_codec instance identified by frame_codec.] */
int frame_codec_subscribe(FRAME_CODEC_HANDLE frame_codec, uint8_t type, ON_FRAME_RECEIVED on_frame_received, void* callback_context)
{
int result;
/* Codes_SRS_FRAME_CODEC_01_034: [If any of the frame_codec or on_frame_received arguments is NULL, frame_codec_subscribe shall return a non-zero value.] */
if ((frame_codec == NULL) ||
(on_frame_received == NULL))
{
result = __LINE__;
}
else
{
FRAME_CODEC_INSTANCE* frame_codec_data = (FRAME_CODEC_INSTANCE*)frame_codec;
SUBSCRIPTION* subscription;
/* Codes_SRS_FRAME_CODEC_01_036: [Only one callback pair shall be allowed to be registered for a given frame type.] */
/* find the subscription for this frame type */
LIST_ITEM_HANDLE list_item = list_find(frame_codec_data->subscription_list, find_subscription_by_frame_type, &type);
if (list_item != NULL)
{
subscription = (SUBSCRIPTION*)list_item_get_value(list_item);
if (subscription == NULL)
{
/* Codes_SRS_FRAME_CODEC_01_037: [If any failure occurs while performing the subscribe operation, frame_codec_subscribe shall return a non-zero value.] */
result = __LINE__;
}
else
{
/* a subscription was found */
subscription->on_frame_received = on_frame_received;
subscription->callback_context = callback_context;
/* Codes_SRS_FRAME_CODEC_01_087: [On success, frame_codec_subscribe shall return zero.] */
result = 0;
}
}
else
{
/* add a new subscription */
subscription = (SUBSCRIPTION*)amqpalloc_malloc(sizeof(SUBSCRIPTION));
/* Codes_SRS_FRAME_CODEC_01_037: [If any failure occurs while performing the subscribe operation, frame_codec_subscribe shall return a non-zero value.] */
if (subscription == NULL)
{
result = __LINE__;
}
else
{
subscription->on_frame_received = on_frame_received;
subscription->callback_context = callback_context;
subscription->frame_type = type;
/* Codes_SRS_FRAME_CODEC_01_037: [If any failure occurs while performing the subscribe operation, frame_codec_subscribe shall return a non-zero value.] */
if (list_add(frame_codec_data->subscription_list, subscription) == NULL)
{
amqpalloc_free(subscription);
result = __LINE__;
}
else
{
/* Codes_SRS_FRAME_CODEC_01_087: [On success, frame_codec_subscribe shall return zero.] */
result = 0;
}
}
}
}
return result;
}
int frame_codec_unsubscribe(FRAME_CODEC_HANDLE frame_codec, uint8_t type)
{
int result;
/* Codes_SRS_FRAME_CODEC_01_039: [If frame_codec is NULL, frame_codec_unsubscribe shall return a non-zero value.] */
if (frame_codec == NULL)
{
result = __LINE__;
}
else
{
FRAME_CODEC_INSTANCE* frame_codec_data = (FRAME_CODEC_INSTANCE*)frame_codec;
LIST_ITEM_HANDLE list_item = list_find(frame_codec_data->subscription_list, find_subscription_by_frame_type, &type);
if (list_item == NULL)
{
/* Codes_SRS_FRAME_CODEC_01_040: [If no subscription for the type frame type exists, frame_codec_unsubscribe shall return a non-zero value.] */
/* Codes_SRS_FRAME_CODEC_01_041: [If any failure occurs while performing the unsubscribe operation, frame_codec_unsubscribe shall return a non-zero value.] */
result = __LINE__;
}
else
{
SUBSCRIPTION* subscription = (SUBSCRIPTION*)list_item_get_value(list_item);
if (subscription == NULL)
{
/* Codes_SRS_FRAME_CODEC_01_041: [If any failure occurs while performing the unsubscribe operation, frame_codec_unsubscribe shall return a non-zero value.] */
result = __LINE__;
}
else
{
amqpalloc_free(subscription);
if (list_remove(frame_codec_data->subscription_list, list_item) != 0)
{
/* Codes_SRS_FRAME_CODEC_01_041: [If any failure occurs while performing the unsubscribe operation, frame_codec_unsubscribe shall return a non-zero value.] */
result = __LINE__;
}
else
{
/* Codes_SRS_FRAME_CODEC_01_038: [frame_codec_unsubscribe removes a previous subscription for frames of type type and on success it shall return 0.] */
result = 0;
}
}
}
}
return result;
}
int frame_codec_encode_frame(FRAME_CODEC_HANDLE frame_codec, uint8_t type, const PAYLOAD* payloads, size_t payload_count, const unsigned char* type_specific_bytes, uint32_t type_specific_size, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context)
{
int result;
uint32_t frame_body_offset = type_specific_size + 6;
/* round up to the 4 bytes for doff */
/* Codes_SRS_FRAME_CODEC_01_067: [The value of the data offset is an unsigned, 8-bit integer specifying a count of 4-byte words.] */
/* Codes_SRS_FRAME_CODEC_01_068: [Due to the mandatory 8-byte frame header, the frame is malformed if the value is less than 2.] */
uint8_t doff = (frame_body_offset + 3) / 4;
size_t frame_size;
FRAME_CODEC_INSTANCE* frame_codec_data = (FRAME_CODEC_INSTANCE*)frame_codec;
uint32_t frame_body_size = 0;
size_t i;
for (i = 0; i < payload_count; i++)
{
frame_body_size += payloads[i].length;
}
frame_body_offset = doff * 4;
/* Codes_SRS_FRAME_CODEC_01_063: [This is an unsigned 32-bit integer that MUST contain the total frame size of the frame header, extended header, and frame body.] */
frame_size = frame_body_size + frame_body_offset;
/* Codes_SRS_FRAME_CODEC_01_044: [If the argument frame_codec is NULL, frame_codec_encode_frame shall return a non-zero value.] */
if ((frame_codec == NULL) ||
/* Codes_SRS_FRAME_CODEC_01_091: [If the argument type_specific_size is greater than 0 and type_specific_bytes is NULL, frame_codec_encode_frame shall return a non-zero value.] */
((type_specific_size > 0) && (type_specific_bytes == NULL)) ||
/* Codes_SRS_FRAME_CODEC_01_092: [If type_specific_size is too big to allow encoding the frame according to the AMQP ISO then frame_codec_encode_frame shall return a non-zero value.] */
(type_specific_size > MAX_TYPE_SPECIFIC_SIZE) ||
(frame_codec_data->encode_frame_state == ENCODE_FRAME_STATE_ERROR) ||
/* Codes_SRS_FRAME_CODEC_01_095: [If the frame_size needed for the frame is bigger than the maximum frame size, frame_codec_encode_frame shall fail and return a non-zero value.] */
(frame_size > frame_codec_data->max_frame_size))
{
result = __LINE__;
}
else
{
uint8_t padding_byte_count = frame_body_offset - type_specific_size - 6;
/* Codes_SRS_FRAME_CODEC_01_042: [frame_codec_encode_frame encodes the header and type specific bytes of a frame that has frame_payload_size bytes.] */
/* Codes_SRS_FRAME_CODEC_01_055: [Frames are divided into three distinct areas: a fixed width frame header, a variable width extended header, and a variable width frame body.] */
/* Codes_SRS_FRAME_CODEC_01_056: [frame header The frame header is a fixed size (8 byte) structure that precedes each frame.] */
/* Codes_SRS_FRAME_CODEC_01_057: [The frame header includes mandatory information necessary to parse the rest of the frame including size and type information.] */
/* Codes_SRS_FRAME_CODEC_01_058: [extended header The extended header is a variable width area preceding the frame body.] */
/* Codes_SRS_FRAME_CODEC_01_059: [This is an extension point defined for future expansion.] */
/* Codes_SRS_FRAME_CODEC_01_060: [The treatment of this area depends on the frame type.]*/
/* Codes_SRS_FRAME_CODEC_01_062: [SIZE Bytes 0-3 of the frame header contain the frame size.] */
/* Codes_SRS_FRAME_CODEC_01_063: [This is an unsigned 32-bit integer that MUST contain the total frame size of the frame header, extended header, and frame body.] */
/* Codes_SRS_FRAME_CODEC_01_064: [The frame is malformed if the size is less than the size of the frame header (8 bytes).] */
unsigned char frame_header[] =
{
(frame_size >> 24) & 0xFF,
(frame_size >> 16) & 0xFF,
(frame_size >> 8) & 0xFF,
frame_size & 0xFF,
/* Codes_SRS_FRAME_CODEC_01_065: [DOFF Byte 4 of the frame header is the data offset.] */
doff,
/* Codes_SRS_FRAME_CODEC_01_069: [TYPE Byte 5 of the frame header is a type code.] */
type
};
/* Codes_SRS_FRAME_CODEC_01_088: [Encoded bytes shall be passed to the on_bytes_encoded callback.] */
on_bytes_encoded(callback_context, frame_header, sizeof(frame_header), ((frame_body_size + type_specific_bytes + padding_byte_count) == 0) ? true : false);
/* Codes_SRS_FRAME_CODEC_01_088: [Encoded bytes shall be passed to the on_bytes_encoded callback.] */
if (type_specific_size > 0)
{
on_bytes_encoded(callback_context, type_specific_bytes, type_specific_size, ((frame_body_size + padding_byte_count) == 0) ? true : false);
}
/* send padding bytes */
/* Codes_SRS_FRAME_CODEC_01_090: [If the type_specific_size – 2 does not divide by 4, frame_codec_encode_frame shall pad the type_specific bytes with zeroes so that type specific data is according to the AMQP ISO.] */
unsigned char padding_bytes[] = { 0x00, 0x00, 0x00 };
/* Codes_SRS_FRAME_CODEC_01_088: [Encoded bytes shall be passed to the on_bytes_encoded callback.] */
if (padding_byte_count > 0)
{
on_bytes_encoded(callback_context, padding_bytes, padding_byte_count, (payload_count == 0) ? true : false);
}
for (i = 0; i < payload_count; i++)
{
/* Codes_SRS_FRAME_CODEC_01_088: [Encoded bytes shall be passed to the on_bytes_encoded callback.] */
on_bytes_encoded(callback_context, payloads[i].bytes, payloads[i].length, (i == payload_count - 1) ? true : false);
}
/* Codes_SRS_FRAME_CODEC_01_043: [On success it shall return 0.] */
result = 0;
}
return result;
}

264
src/header_detect_io.c Normal file
Просмотреть файл

@ -0,0 +1,264 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include "header_detect_io.h"
#include "amqpalloc.h"
typedef struct HEADER_DETECT_IO_INSTANCE_TAG
{
XIO_HANDLE underlying_io;
size_t header_pos;
IO_STATE io_state;
ON_IO_STATE_CHANGED on_io_state_changed;
ON_BYTES_RECEIVED on_bytes_received;
void* callback_context;
} HEADER_DETECT_IO_INSTANCE;
static const unsigned char amqp_header[] = { 'A', 'M', 'Q', 'P', 0, 1, 0, 0 };
static void set_io_state(HEADER_DETECT_IO_INSTANCE* header_detect_io_instance, IO_STATE io_state)
{
IO_STATE previous_state = header_detect_io_instance->io_state;
header_detect_io_instance->io_state = io_state;
if (header_detect_io_instance->on_io_state_changed != NULL)
{
header_detect_io_instance->on_io_state_changed(header_detect_io_instance->callback_context, io_state, previous_state);
}
}
static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size)
{
HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)context;
while (size > 0)
{
switch (header_detect_io_instance->io_state)
{
default:
set_io_state(header_detect_io_instance, IO_STATE_ERROR);
break;
case IO_STATE_OPENING:
if (amqp_header[header_detect_io_instance->header_pos] != buffer[0])
{
set_io_state(header_detect_io_instance, IO_STATE_ERROR);
size = 0;
}
else
{
header_detect_io_instance->header_pos++;
size--;
buffer++;
if (header_detect_io_instance->header_pos == sizeof(amqp_header))
{
if (xio_send(header_detect_io_instance->underlying_io, amqp_header, sizeof(amqp_header), NULL, NULL) != 0)
{
set_io_state(header_detect_io_instance, IO_STATE_ERROR);
}
else
{
set_io_state(header_detect_io_instance, IO_STATE_OPEN);
}
}
}
break;
case IO_STATE_OPEN:
header_detect_io_instance->on_bytes_received(header_detect_io_instance->callback_context, buffer, size);
size = 0;
break;
}
}
}
static void on_underlying_io_state_changed(void* context, IO_STATE new_io_state, IO_STATE previous_io_state)
{
HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)context;
switch (new_io_state)
{
default:
break;
case IO_STATE_ERROR:
set_io_state(header_detect_io_instance, IO_STATE_ERROR);
break;
}
}
CONCRETE_IO_HANDLE headerdetectio_create(void* io_create_parameters, LOGGER_LOG logger_log)
{
HEADER_DETECT_IO_INSTANCE* result;
if (io_create_parameters == NULL)
{
result = NULL;
}
else
{
HEADERDETECTIO_CONFIG* header_detect_io_config = (HEADERDETECTIO_CONFIG*)io_create_parameters;
result = (HEADER_DETECT_IO_INSTANCE*)amqpalloc_malloc(sizeof(HEADER_DETECT_IO_INSTANCE));
if (result != NULL)
{
result->underlying_io = header_detect_io_config->underlying_io;
result->on_io_state_changed = NULL;
result->on_bytes_received = NULL;
result->callback_context = NULL;
set_io_state(result, IO_STATE_NOT_OPEN);
}
}
return result;
}
void headerdetectio_destroy(CONCRETE_IO_HANDLE header_detect_io)
{
if (header_detect_io != NULL)
{
HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)header_detect_io;
(void)headerdetectio_close(header_detect_io);
xio_destroy(header_detect_io_instance->underlying_io);
amqpalloc_free(header_detect_io);
}
}
int headerdetectio_open(CONCRETE_IO_HANDLE header_detect_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context)
{
int result;
if (header_detect_io == NULL)
{
result = __LINE__;
}
else
{
HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)header_detect_io;
if (header_detect_io_instance->io_state == IO_STATE_OPEN)
{
header_detect_io_instance->on_bytes_received = on_bytes_received;
header_detect_io_instance->on_io_state_changed = on_io_state_changed;
header_detect_io_instance->callback_context = callback_context;
result = 0;
}
else if (header_detect_io_instance->io_state != IO_STATE_NOT_OPEN)
{
result = __LINE__;
}
else
{
header_detect_io_instance->header_pos = 0;
set_io_state(header_detect_io_instance, IO_STATE_OPENING);
if (xio_open(header_detect_io_instance->underlying_io, on_underlying_io_bytes_received, on_underlying_io_state_changed, header_detect_io_instance) != 0)
{
result = __LINE__;
}
else
{
header_detect_io_instance->on_bytes_received = on_bytes_received;
header_detect_io_instance->on_io_state_changed = on_io_state_changed;
header_detect_io_instance->callback_context = callback_context;
result = 0;
}
}
}
return result;
}
int headerdetectio_close(CONCRETE_IO_HANDLE header_detect_io)
{
int result;
if (header_detect_io == NULL)
{
result = __LINE__;
}
else
{
HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)header_detect_io;
if (header_detect_io_instance->io_state == IO_STATE_NOT_OPEN)
{
result = __LINE__;
}
else
{
if (xio_close(header_detect_io_instance->underlying_io) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
int headerdetectio_send(CONCRETE_IO_HANDLE header_detect_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
{
int result;
if (header_detect_io == NULL)
{
result = __LINE__;
}
else
{
HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)header_detect_io;
if (header_detect_io_instance->io_state != IO_STATE_OPEN)
{
result = __LINE__;
}
else
{
if (xio_send(header_detect_io_instance->underlying_io, buffer, size, on_send_complete, callback_context) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
void headerdetectio_dowork(CONCRETE_IO_HANDLE header_detect_io)
{
if (header_detect_io != NULL)
{
HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)header_detect_io;
if ((header_detect_io_instance->io_state != IO_STATE_NOT_OPEN) &&
(header_detect_io_instance->io_state != IO_STATE_ERROR))
{
xio_dowork(header_detect_io_instance->underlying_io);
}
}
}
static const IO_INTERFACE_DESCRIPTION header_detect_io_interface_description =
{
headerdetectio_create,
headerdetectio_destroy,
headerdetectio_open,
headerdetectio_close,
headerdetectio_send,
headerdetectio_dowork
};
const IO_INTERFACE_DESCRIPTION* headerdetectio_get_interface_description(void)
{
return &header_detect_io_interface_description;
}

164
src/io.c Normal file
Просмотреть файл

@ -0,0 +1,164 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stddef.h>
#include "io.h"
#include "amqpalloc.h"
typedef struct IO_INSTANCE_TAG
{
const IO_INTERFACE_DESCRIPTION* io_interface_description;
IO_HANDLE concrete_io_handle;
} IO_INSTANCE;
IO_HANDLE io_create(const IO_INTERFACE_DESCRIPTION* io_interface_description, const void* io_create_parameters, LOGGER_LOG logger_log)
{
IO_INSTANCE* io_instance;
/* Codes_SRS_IO_01_003: [If the argument io_interface_description is NULL, io_create shall return NULL.] */
if ((io_interface_description == NULL) ||
/* Codes_SRS_IO_01_004: [If any io_interface_description member is NULL, io_create shall return NULL.] */
(io_interface_description->concrete_io_create == NULL) ||
(io_interface_description->concrete_io_destroy == NULL) ||
(io_interface_description->concrete_io_open == NULL) ||
(io_interface_description->concrete_io_close == NULL) ||
(io_interface_description->concrete_io_send == NULL) ||
(io_interface_description->concrete_io_dowork == NULL))
{
io_instance = NULL;
}
else
{
io_instance = (IO_INSTANCE*)amqpalloc_malloc(sizeof(IO_INSTANCE));
/* Codes_SRS_IO_01_017: [If allocating the memory needed for the IO interface fails then io_create shall return NULL.] */
if (io_instance != NULL)
{
/* Codes_SRS_IO_01_001: [io_create shall return on success a non-NULL handle to a new IO interface.] */
io_instance->io_interface_description = io_interface_description;
/* Codes_SRS_IO_01_002: [In order to instantiate the concrete IO implementation the function concrete_io_create from the io_interface_description shall be called, passing the io_create_parameters and logger_log arguments.] */
io_instance->concrete_io_handle = io_instance->io_interface_description->concrete_io_create((void*)io_create_parameters, logger_log);
/* Codes_SRS_IO_01_016: [If the underlying concrete_io_create call fails, io_create shall return NULL.] */
if (io_instance->concrete_io_handle == NULL)
{
amqpalloc_free(io_instance);
io_instance = NULL;
}
}
}
return (IO_HANDLE)io_instance;
}
void io_destroy(IO_HANDLE io)
{
/* Codes_SRS_IO_01_007: [If the argument io is NULL, io_destroy shall do nothing.] */
if (io != NULL)
{
IO_INSTANCE* io_instance = (IO_INSTANCE*)io;
/* Codes_SRS_IO_01_006: [io_destroy shall also call the concrete_io_destroy function that is member of the io_interface_description argument passed to io_create, while passing as argument to concrete_io_destroy the result of the underlying concrete_io_create handle that was called as part of the io_create call.] */
io_instance->io_interface_description->concrete_io_destroy(io_instance->concrete_io_handle);
/* Codes_SRS_IO_01_005: [io_destroy shall free all resources associated with the IO handle.] */
amqpalloc_free(io_instance);
}
}
int io_open(IO_HANDLE io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context)
{
int result;
if (io == NULL)
{
/* Codes_SRS_IO_01_021: [If the argument io is NULL, io_open shall return a non-zero value.] */
result = __LINE__;
}
else
{
IO_INSTANCE* io_instance = (IO_INSTANCE*)io;
/* Codes_SRS_IO_01_019: [io_open shall call the specific concrete_io_open function specified in io_create, passing the receive_callback and receive_callback_context arguments.] */
if (io_instance->io_interface_description->concrete_io_open(io_instance->concrete_io_handle, on_bytes_received, on_io_state_changed, callback_context) != 0)
{
/* Codes_SRS_IO_01_022: [If the underlying concrete_io_open fails, io_open shall return a non-zero value.] */
result = __LINE__;
}
else
{
/* Codes_SRS_IO_01_020: [On success, io_open shall return 0.] */
result = 0;
}
}
return result;
}
int io_close(IO_HANDLE io)
{
int result;
if (io == NULL)
{
/* Codes_SRS_IO_01_025: [If the argument io is NULL, io_close shall return a non-zero value.] */
result = __LINE__;
}
else
{
IO_INSTANCE* io_instance = (IO_INSTANCE*)io;
/* Codes_SRS_IO_01_023: [io_close shall call the specific concrete_io_close function specified in io_create.] */
if (io_instance->io_interface_description->concrete_io_close(io_instance->concrete_io_handle) != 0)
{
/* Codes_SRS_IO_01_026: [If the underlying concrete_io_close fails, io_close shall return a non-zero value.] */
result = __LINE__;
}
else
{
/* Codes_SRS_IO_01_024: [On success, io_close shall return 0.] */
result = 0;
}
}
return result;
}
int io_send(IO_HANDLE io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
{
int result;
/* Codes_SRS_IO_01_011: [No error check shall be performed on buffer and size.] */
/* Codes_SRS_IO_01_010: [If the argument io is NULL, io_send shall return a non-zero value.] */
if (io == NULL)
{
result = __LINE__;
}
else
{
IO_INSTANCE* io_instance = (IO_INSTANCE*)io;
/* Codes_SRS_IO_01_008: [io_send shall pass the sequence of bytes pointed to by buffer to the concrete IO implementation specified in io_create, by calling the concrete_io_send function while passing down the buffer and size arguments to it.] */
/* Codes_SRS_IO_01_009: [On success, io_send shall return 0.] */
/* Codes_SRS_IO_01_015: [If the underlying concrete_io_send fails, io_send shall return a non-zero value.] */
/* Codes_SRS_IO_01_027: [io_send shall pass to the concrete_io_send function the on_send_complete and callback_context arguments.] */
result = io_instance->io_interface_description->concrete_io_send(io_instance->concrete_io_handle, buffer, size, on_send_complete, callback_context);
}
return result;
}
void io_dowork(IO_HANDLE io)
{
/* Codes_SRS_IO_01_018: [When the io argument is NULL, io_dowork shall do nothing.] */
if (io != NULL)
{
IO_INSTANCE* io_instance = (IO_INSTANCE*)io;
/* Codes_SRS_IO_01_012: [io_dowork shall call the concrete IO implementation specified in io_create, by calling the concrete_io_dowork function.] */
io_instance->io_interface_description->concrete_io_dowork(io_instance->concrete_io_handle);
}
}

938
src/link.c Normal file
Просмотреть файл

@ -0,0 +1,938 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "link.h"
#include "session.h"
#include "amqpvalue.h"
#include "amqp_definitions.h"
#include "amqpalloc.h"
#include "amqp_frame_codec.h"
#include "consolelogger.h"
#include "logger.h"
#include "list.h"
#define DEFAULT_LINK_CREDIT 10000
typedef struct DELIVERY_INSTANCE_TAG
{
delivery_number delivery_id;
ON_DELIVERY_SETTLED on_delivery_settled;
void* callback_context;
void* link;
} DELIVERY_INSTANCE;
typedef struct LINK_INSTANCE_TAG
{
SESSION_HANDLE session;
LINK_STATE link_state;
LINK_STATE previous_link_state;
AMQP_VALUE source;
AMQP_VALUE target;
handle handle;
LINK_ENDPOINT_HANDLE link_endpoint;
char* name;
LIST_HANDLE pending_deliveries;
sequence_no delivery_count;
role role;
ON_LINK_STATE_CHANGED on_link_state_changed;
ON_LINK_FLOW_ON on_link_flow_on;
ON_TRANSFER_RECEIVED on_transfer_received;
void* callback_context;
sender_settle_mode snd_settle_mode;
receiver_settle_mode rcv_settle_mode;
sequence_no initial_delivery_count;
uint64_t max_message_size;
uint32_t link_credit;
uint32_t available;
unsigned char is_underlying_session_begun : 1;
} LINK_INSTANCE;
static void set_link_state(LINK_INSTANCE* link_instance, LINK_STATE link_state)
{
link_instance->previous_link_state = link_instance->link_state;
link_instance->link_state = link_state;
if (link_instance->on_link_state_changed != NULL)
{
link_instance->on_link_state_changed(link_instance->callback_context, link_state, link_instance->previous_link_state);
}
}
static int send_flow(LINK_INSTANCE* link)
{
int result;
FLOW_HANDLE flow = flow_create(0, 0, 0);
if (flow == NULL)
{
result = __LINE__;
}
else
{
if ((flow_set_link_credit(flow, link->link_credit) != 0) ||
(flow_set_handle(flow, link->handle) != 0) ||
(flow_set_delivery_count(flow, link->delivery_count) != 0))
{
result = __LINE__;
}
else
{
if (session_send_flow(link->link_endpoint, flow) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
flow_destroy(flow);
}
return result;
}
static int send_disposition(LINK_INSTANCE* link_instance, delivery_number delivery_number, AMQP_VALUE delivery_state)
{
int result;
DISPOSITION_HANDLE disposition = disposition_create(link_instance->role, delivery_number);
if (disposition == NULL)
{
result = __LINE__;
}
else
{
if ((disposition_set_last(disposition, delivery_number) != 0) ||
(disposition_set_settled(disposition, true) != 0) ||
((delivery_state != NULL) && (disposition_set_state(disposition, delivery_state) != 0)))
{
result = __LINE__;
}
else
{
if (session_send_disposition(link_instance->link_endpoint, disposition) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
disposition_destroy(disposition);
}
return result;
}
static int send_detach_frame(LINK_INSTANCE* link_instance, ERROR_HANDLE error_handle)
{
int result;
DETACH_HANDLE detach_performative;
detach_performative = detach_create(0);
if (detach_performative == NULL)
{
result = __LINE__;
}
else
{
if ((error_handle != NULL) &&
(detach_set_error(detach_performative, error_handle) != 0))
{
result = __LINE__;
}
else
{
if (session_send_detach(link_instance->link_endpoint, detach_performative) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
detach_destroy(detach_performative);
}
return result;
}
static void link_frame_received(void* context, AMQP_VALUE performative, uint32_t payload_size, const unsigned char* payload_bytes)
{
LINK_INSTANCE* link_instance = (LINK_INSTANCE*)context;
AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
if (is_attach_type_by_descriptor(descriptor))
{
ATTACH_HANDLE attach_handle;
if (amqpvalue_get_attach(performative, &attach_handle) == 0)
{
if ((link_instance->role == role_receiver) &&
(attach_get_initial_delivery_count(attach_handle, &link_instance->delivery_count) != 0))
{
/* error */
set_link_state(link_instance, LINK_STATE_DETACHED);
}
else
{
if (link_instance->link_state == LINK_STATE_HALF_ATTACHED)
{
if (link_instance->role == role_receiver)
{
link_instance->link_credit = DEFAULT_LINK_CREDIT;
send_flow(link_instance);
}
else
{
link_instance->link_credit = 0;
}
set_link_state(link_instance, LINK_STATE_ATTACHED);
}
}
attach_destroy(attach_handle);
}
}
else if (is_flow_type_by_descriptor(descriptor))
{
FLOW_HANDLE flow_handle;
if (amqpvalue_get_flow(performative, &flow_handle) == 0)
{
if (link_instance->role == role_sender)
{
delivery_number rcv_delivery_count;
uint32_t rcv_link_credit;
if ((flow_get_link_credit(flow_handle, &rcv_link_credit) != 0) ||
(flow_get_delivery_count(flow_handle, &rcv_delivery_count) != 0))
{
/* error */
set_link_state(link_instance, LINK_STATE_DETACHED);
}
else
{
link_instance->link_credit = rcv_delivery_count + rcv_link_credit - link_instance->delivery_count;
if (link_instance->link_credit > 0)
{
link_instance->on_link_flow_on(link_instance->callback_context);
}
}
}
}
flow_destroy(flow_handle);
}
else if (is_transfer_type_by_descriptor(descriptor))
{
if (link_instance->on_transfer_received != NULL)
{
TRANSFER_HANDLE transfer_handle;
if (amqpvalue_get_transfer(performative, &transfer_handle) == 0)
{
AMQP_VALUE delivery_state;
delivery_number received_delivery_id;
link_instance->link_credit--;
link_instance->delivery_count++;
if (link_instance->link_credit == 0)
{
link_instance->link_credit = DEFAULT_LINK_CREDIT;
send_flow(link_instance);
}
if (transfer_get_delivery_id(transfer_handle, &received_delivery_id) != 0)
{
/* error */
}
else
{
delivery_state = link_instance->on_transfer_received(link_instance->callback_context, transfer_handle, payload_size, payload_bytes);
if (send_disposition(link_instance, received_delivery_id, delivery_state) != 0)
{
/* error */
}
if (delivery_state != NULL)
{
amqpvalue_destroy(delivery_state);
}
}
transfer_destroy(transfer_handle);
}
}
}
else if (is_disposition_type_by_descriptor(descriptor))
{
DISPOSITION_HANDLE disposition;
if (amqpvalue_get_disposition(performative, &disposition) != 0)
{
/* error */
}
else
{
delivery_number first;
delivery_number last;
if (disposition_get_first(disposition, &first) != 0)
{
/* error */
}
else
{
if (disposition_get_last(disposition, &last) != 0)
{
last = first;
}
LIST_ITEM_HANDLE pending_delivery = list_get_head_item(link_instance->pending_deliveries);
while (pending_delivery != NULL)
{
LIST_ITEM_HANDLE next_pending_delivery = list_get_next_item(pending_delivery);
DELIVERY_INSTANCE* delivery_instance = (DELIVERY_INSTANCE*)list_item_get_value(pending_delivery);
if (delivery_instance == NULL)
{
/* error */
break;
}
else
{
delivery_instance->on_delivery_settled(delivery_instance->callback_context, delivery_instance->delivery_id);
amqpalloc_free(delivery_instance);
if (list_remove(link_instance->pending_deliveries, pending_delivery) != 0)
{
/* error */
break;
}
else
{
pending_delivery = next_pending_delivery;
}
}
}
}
disposition_destroy(disposition);
}
}
else if (is_detach_type_by_descriptor(descriptor))
{
if (send_detach_frame(link_instance, NULL) != 0)
{
/* error */
}
}
}
static int send_attach(LINK_INSTANCE* link, const char* name, handle handle, role role)
{
int result;
ATTACH_HANDLE attach = attach_create(name, handle, role);
if (attach == NULL)
{
result = __LINE__;
}
else
{
result = 0;
link->delivery_count = link->initial_delivery_count;
attach_set_snd_settle_mode(attach, link->snd_settle_mode);
attach_set_rcv_settle_mode(attach, link->rcv_settle_mode);
attach_set_role(attach, role);
attach_set_source(attach, link->source);
attach_set_target(attach, link->target);
if (role == role_sender)
{
if (attach_set_initial_delivery_count(attach, link->delivery_count) != 0)
{
result = __LINE__;
}
}
if (result == 0)
{
if ((attach_set_max_message_size(attach, link->max_message_size) != 0) ||
(session_send_attach(link->link_endpoint, attach) != 0))
{
result = __LINE__;
}
else
{
result = 0;
}
}
attach_destroy(attach);
}
return result;
}
static int send_detach(LINK_INSTANCE* link_instance, ERROR_HANDLE error)
{
int result;
DETACH_HANDLE detach = detach_create(0);
if (detach == NULL)
{
result = __LINE__;
}
else
{
if (((error != NULL) && (detach_set_error(detach, error) != 0)) ||
(session_send_detach(link_instance->link_endpoint, detach) != 0))
{
result = __LINE__;
}
else
{
result = 0;
}
detach_destroy(detach);
}
return result;
}
static void on_session_state_changed(void* context, SESSION_STATE new_session_state, SESSION_STATE previous_session_state)
{
LINK_INSTANCE* link_instance = (LINK_INSTANCE*)context;
if (new_session_state == SESSION_STATE_MAPPED)
{
if (link_instance->link_state == LINK_STATE_DETACHED)
{
if (send_attach(link_instance, link_instance->name, 0, link_instance->role) == 0)
{
set_link_state(link_instance, LINK_STATE_HALF_ATTACHED);
}
}
}
else if (new_session_state == SESSION_STATE_DISCARDING)
{
set_link_state(link_instance, LINK_STATE_DETACHED);
}
}
static void on_session_flow_on(void* context)
{
LINK_INSTANCE* link_instance = (LINK_INSTANCE*)context;
if (link_instance->role == role_sender)
{
link_instance->on_link_flow_on(link_instance->callback_context);
}
}
static void on_send_complete(void* context, IO_SEND_RESULT send_result)
{
LIST_ITEM_HANDLE delivery_instance_list_item = (LIST_ITEM_HANDLE)context;
DELIVERY_INSTANCE* delivery_instance = (DELIVERY_INSTANCE*)list_item_get_value(delivery_instance_list_item);
LINK_INSTANCE* link_instance = (LINK_INSTANCE*)delivery_instance->link;
if (link_instance->snd_settle_mode == sender_settle_mode_settled)
{
delivery_instance->on_delivery_settled(delivery_instance->callback_context, delivery_instance->delivery_id);
amqpalloc_free(delivery_instance);
(void)list_remove(link_instance->pending_deliveries, delivery_instance_list_item);
}
}
LINK_HANDLE link_create(SESSION_HANDLE session, const char* name, role role, AMQP_VALUE source, AMQP_VALUE target)
{
LINK_INSTANCE* result = amqpalloc_malloc(sizeof(LINK_INSTANCE));
if (result != NULL)
{
result->link_state = LINK_STATE_DETACHED;
result->previous_link_state = LINK_STATE_DETACHED;
result->role = role;
result->source = amqpvalue_clone(source);
result->target = amqpvalue_clone(target);
result->session = session;
result->handle = 0;
result->snd_settle_mode = sender_settle_mode_unsettled;
result->rcv_settle_mode = receiver_settle_mode_first;
result->delivery_count = 0;
result->initial_delivery_count = 0;
result->max_message_size = 0;
result->is_underlying_session_begun = 0;
result->pending_deliveries = list_create();
if (result->pending_deliveries == NULL)
{
amqpalloc_free(result);
result = NULL;
}
else
{
result->name = amqpalloc_malloc(strlen(name) + 1);
if (result->name == NULL)
{
list_destroy(result->pending_deliveries);
amqpalloc_free(result);
result = NULL;
}
else
{
result->on_link_state_changed = NULL;
result->callback_context = NULL;
set_link_state(result, LINK_STATE_DETACHED);
(void)strcpy(result->name, name);
result->link_endpoint = session_create_link_endpoint(session, name);
if (result->link_endpoint == NULL)
{
list_destroy(result->pending_deliveries);
amqpalloc_free(result->name);
amqpalloc_free(result);
result = NULL;
}
}
}
}
return result;
}
LINK_HANDLE link_create_from_endpoint(SESSION_HANDLE session, LINK_ENDPOINT_HANDLE link_endpoint, const char* name, role role, AMQP_VALUE source, AMQP_VALUE target)
{
LINK_INSTANCE* result = amqpalloc_malloc(sizeof(LINK_INSTANCE));
if (result != NULL)
{
result->link_state = LINK_STATE_DETACHED;
result->previous_link_state = LINK_STATE_DETACHED;
result->session = session;
result->handle = 0;
result->snd_settle_mode = sender_settle_mode_unsettled;
result->rcv_settle_mode = receiver_settle_mode_first;
result->delivery_count = 0;
result->initial_delivery_count = 0;
result->max_message_size = 0;
result->is_underlying_session_begun = 0;
result->source = amqpvalue_clone(target);
result->target = amqpvalue_clone(source);
if (role == role_sender)
{
result->role = role_receiver;
}
else
{
result->role = role_sender;
}
result->pending_deliveries = list_create();
if (result->pending_deliveries == NULL)
{
amqpalloc_free(result);
result = NULL;
}
else
{
result->name = amqpalloc_malloc(strlen(name) + 1);
if (result->name == NULL)
{
list_destroy(result->pending_deliveries);
amqpalloc_free(result);
result = NULL;
}
else
{
(void)strcpy(result->name, name);
result->on_link_state_changed = NULL;
result->callback_context = NULL;
set_link_state(result, LINK_STATE_HALF_ATTACHED);
result->link_endpoint = link_endpoint;
}
}
}
return result;
}
void link_destroy(LINK_HANDLE link)
{
if (link != NULL)
{
link_detach(link);
session_destroy_link_endpoint(link->link_endpoint);
amqpvalue_destroy(link->source);
amqpvalue_destroy(link->target);
if (link->pending_deliveries != NULL)
{
LIST_ITEM_HANDLE item = list_get_head_item(link->pending_deliveries);
while (item != NULL)
{
LIST_ITEM_HANDLE next_item = list_get_next_item(item);
DELIVERY_INSTANCE* delivery_instance = (DELIVERY_INSTANCE*)list_item_get_value(item);
if (delivery_instance != NULL)
{
amqpalloc_free(delivery_instance);
}
item = next_item;
}
list_destroy(link->pending_deliveries);
}
if (link->name != NULL)
{
amqpalloc_free(link->name);
}
amqpalloc_free(link);
}
}
int link_set_snd_settle_mode(LINK_HANDLE link, sender_settle_mode snd_settle_mode)
{
int result;
if (link == NULL)
{
result = __LINE__;
}
else
{
link->snd_settle_mode = snd_settle_mode;
result = 0;
}
return result;
}
int link_get_snd_settle_mode(LINK_HANDLE link, sender_settle_mode* snd_settle_mode)
{
int result;
if ((link == NULL) ||
(snd_settle_mode == NULL))
{
result = __LINE__;
}
else
{
*snd_settle_mode = link->snd_settle_mode;
result = 0;
}
return result;
}
int link_set_rcv_settle_mode(LINK_HANDLE link, receiver_settle_mode rcv_settle_mode)
{
int result;
if (link == NULL)
{
result = __LINE__;
}
else
{
link->rcv_settle_mode = rcv_settle_mode;
result = 0;
}
return result;
}
int link_get_rcv_settle_mode(LINK_HANDLE link, receiver_settle_mode* rcv_settle_mode)
{
int result;
if ((link == NULL) ||
(rcv_settle_mode == NULL))
{
result = __LINE__;
}
else
{
*rcv_settle_mode = link->rcv_settle_mode;
result = 0;
}
return result;
}
int link_set_initial_delivery_count(LINK_HANDLE link, sequence_no initial_delivery_count)
{
int result;
if (link == NULL)
{
result = __LINE__;
}
else
{
link->initial_delivery_count = initial_delivery_count;
result = 0;
}
return result;
}
int link_get_initial_delivery_count(LINK_HANDLE link, sequence_no* initial_delivery_count)
{
int result;
if ((link == NULL) ||
(initial_delivery_count == NULL))
{
result = __LINE__;
}
else
{
*initial_delivery_count = link->initial_delivery_count;
result = 0;
}
return result;
}
int link_set_max_message_size(LINK_HANDLE link, uint64_t max_message_size)
{
int result;
if (link == NULL)
{
result = __LINE__;
}
else
{
link->max_message_size = max_message_size;
result = 0;
}
return result;
}
int link_get_max_message_size(LINK_HANDLE link, uint64_t* max_message_size)
{
int result;
if ((link == NULL) ||
(max_message_size == NULL))
{
result = __LINE__;
}
else
{
*max_message_size = link->max_message_size;
result = 0;
}
return result;
}
int link_attach(LINK_HANDLE link, ON_TRANSFER_RECEIVED on_transfer_received, ON_LINK_STATE_CHANGED on_link_state_changed, ON_LINK_FLOW_ON on_link_flow_on, void* callback_context)
{
int result;
if (link == NULL)
{
result = __LINE__;
}
else
{
if (!link->is_underlying_session_begun)
{
link->on_link_state_changed = on_link_state_changed;
link->on_transfer_received = on_transfer_received;
link->on_link_flow_on = on_link_flow_on;
link->callback_context = callback_context;
if (session_begin(link->session) != 0)
{
result = __LINE__;
}
else
{
link->is_underlying_session_begun = 1;
if (session_start_link_endpoint(link->link_endpoint, link_frame_received, on_session_state_changed, on_session_flow_on, link) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
else
{
result = 0;
}
}
return result;
}
int link_detach(LINK_HANDLE link)
{
int result;
if (link == NULL)
{
result = __LINE__;
}
else
{
if ((link->link_state == LINK_STATE_HALF_ATTACHED) ||
(link->link_state == LINK_STATE_ATTACHED))
{
link->on_link_state_changed = NULL;
if (send_detach(link, NULL) != 0)
{
result = __LINE__;
}
else
{
set_link_state(link, LINK_STATE_DETACHED);
result = 0;
}
}
else
{
set_link_state(link, LINK_STATE_DETACHED);
result = 0;
}
}
return result;
}
LINK_TRANSFER_RESULT link_transfer(LINK_HANDLE link, PAYLOAD* payloads, size_t payload_count, ON_DELIVERY_SETTLED on_delivery_settled, void* callback_context)
{
LINK_TRANSFER_RESULT result;
if (link == NULL)
{
result = LINK_TRANSFER_ERROR;
}
else
{
if (link->role != role_sender)
{
result = LINK_TRANSFER_ERROR;
}
else if (link->link_credit == 0)
{
result = LINK_TRANSFER_BUSY;
}
else
{
TRANSFER_HANDLE transfer = transfer_create(0);
if (transfer == NULL)
{
result = LINK_TRANSFER_ERROR;
}
else
{
unsigned char delivery_tag_bytes[sizeof(link->delivery_count)];
delivery_tag delivery_tag;
bool settled;
(void)memcpy(delivery_tag_bytes, &link->delivery_count, sizeof(link->delivery_count));
link->delivery_count++;
delivery_tag.bytes = &delivery_tag_bytes;
delivery_tag.length = sizeof(delivery_tag_bytes);
if (link->snd_settle_mode == sender_settle_mode_unsettled)
{
settled = false;
}
else
{
settled = true;
}
if ((transfer_set_delivery_tag(transfer, delivery_tag) != 0) ||
(transfer_set_message_format(transfer, 0) != 0) ||
(transfer_set_settled(transfer, settled) != 0))
{
result = LINK_TRANSFER_ERROR;
}
else
{
AMQP_VALUE transfer_value = amqpvalue_create_transfer(transfer);
if (transfer_value == NULL)
{
result = LINK_TRANSFER_ERROR;
}
else
{
DELIVERY_INSTANCE* pending_delivery = amqpalloc_malloc(sizeof(DELIVERY_INSTANCE));
if (pending_delivery == NULL)
{
result = LINK_TRANSFER_ERROR;
}
else
{
LIST_ITEM_HANDLE delivery_instance_list_item;
pending_delivery->on_delivery_settled = on_delivery_settled;
pending_delivery->callback_context = callback_context;
pending_delivery->link = link;
delivery_instance_list_item = list_add(link->pending_deliveries, pending_delivery);
if (delivery_instance_list_item == NULL)
{
amqpalloc_free(pending_delivery);
result = LINK_TRANSFER_ERROR;
}
else
{
/* here we should feed data to the transfer frame */
switch (session_send_transfer(link->link_endpoint, transfer, payloads, payload_count, &pending_delivery->delivery_id, on_send_complete, delivery_instance_list_item))
{
default:
case SESSION_SEND_TRANSFER_ERROR:
result = LINK_TRANSFER_ERROR;
break;
case SESSION_SEND_TRANSFER_BUSY:
result = LINK_TRANSFER_BUSY;
break;
case SESSION_SEND_TRANSFER_OK:
link->link_credit--;
result = LINK_TRANSFER_OK;
break;
}
}
}
amqpvalue_destroy(transfer_value);
}
}
transfer_destroy(transfer);
}
}
}
return result;
}

976
src/message.c Normal file
Просмотреть файл

@ -0,0 +1,976 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <string.h>
#include "message.h"
#include "amqpvalue.h"
#include "amqpalloc.h"
typedef struct BODY_AMQP_DATA_TAG
{
unsigned char* body_data_section_bytes;
size_t body_data_section_length;
} BODY_AMQP_DATA;
typedef struct MESSAGE_INSTANCE_TAG
{
BODY_AMQP_DATA* body_amqp_data_items;
size_t body_amqp_data_count;
AMQP_VALUE* body_amqp_sequence_items;
size_t body_amqp_sequence_count;
AMQP_VALUE body_amqp_value;
HEADER_HANDLE header;
annotations delivery_annotations;
annotations message_annotations;
PROPERTIES_HANDLE properties;
application_properties application_properties;
annotations footer;
} MESSAGE_INSTANCE;
static void free_all_body_data_items(MESSAGE_INSTANCE* message_instance)
{
size_t i;
for (i = 0; i < message_instance->body_amqp_data_count; i++)
{
if (message_instance->body_amqp_data_items[i].body_data_section_bytes != NULL)
{
amqpalloc_free(message_instance->body_amqp_data_items[i].body_data_section_bytes);
}
}
amqpalloc_free(message_instance->body_amqp_data_items);
message_instance->body_amqp_data_count = 0;
message_instance->body_amqp_data_items = NULL;
}
static void free_all_body_sequence_items(MESSAGE_INSTANCE* message_instance)
{
size_t i;
for (i = 0; i < message_instance->body_amqp_sequence_count; i++)
{
if (message_instance->body_amqp_sequence_items[i] != NULL)
{
amqpvalue_destroy(message_instance->body_amqp_sequence_items[i]);
}
}
amqpalloc_free(message_instance->body_amqp_sequence_items);
message_instance->body_amqp_sequence_count = 0;
message_instance->body_amqp_sequence_items = NULL;
}
MESSAGE_HANDLE message_create(void)
{
MESSAGE_INSTANCE* result = (MESSAGE_INSTANCE*)amqpalloc_malloc(sizeof(MESSAGE_INSTANCE));
/* Codes_SRS_MESSAGE_01_002: [If allocating memory for the message fails, message_create shall fail and return NULL.] */
if (result != NULL)
{
result->header = NULL;
result->delivery_annotations = NULL;
result->message_annotations = NULL;
result->properties = NULL;
result->application_properties = NULL;
result->footer = NULL;
result->body_amqp_data_items = NULL;
result->body_amqp_data_count = 0;
result->body_amqp_value = NULL;
result->body_amqp_sequence_items = NULL;
result->body_amqp_sequence_count = 0;
}
/* Codes_SRS_MESSAGE_01_001: [message_create shall create a new AMQP message instance and on success it shall return a non-NULL handle for the newly created message instance.] */
return result;
}
MESSAGE_HANDLE message_clone(MESSAGE_HANDLE source_message)
{
MESSAGE_INSTANCE* result;
/* Codes_SRS_MESSAGE_01_062: [If source_message is NULL, message_clone shall fail and return NULL.] */
if (source_message == NULL)
{
result = NULL;
}
else
{
MESSAGE_INSTANCE* source_message_instance = (MESSAGE_INSTANCE*)source_message;
result = (MESSAGE_INSTANCE*)message_create();
/* Codes_SRS_MESSAGE_01_003: [message_clone shall clone a message entirely and on success return a non-NULL handle to the cloned message.] */
/* Codes_SRS_MESSAGE_01_004: [If allocating memory for the new cloned message fails, message_clone shall fail and return NULL.] */
if (result != NULL)
{
if (source_message_instance->header != NULL)
{
/* Codes_SRS_MESSAGE_01_005: [If a header exists on the source message it shall be cloned by using header_clone.] */
result->header = header_clone(source_message_instance->header);
if (result->header == NULL)
{
message_destroy(result);
result = NULL;
}
}
if ((result != NULL) && (source_message_instance->delivery_annotations != NULL))
{
/* Codes_SRS_MESSAGE_01_006: [If delivery annotations exist on the source message they shall be cloned by using annotations_clone.] */
result->delivery_annotations = annotations_clone(source_message_instance->delivery_annotations);
if (result->delivery_annotations == NULL)
{
message_destroy(result);
result = NULL;
}
}
if ((result != NULL) && (source_message_instance->message_annotations != NULL))
{
/* Codes_SRS_MESSAGE_01_007: [If message annotations exist on the source message they shall be cloned by using annotations_clone.] */
result->message_annotations = annotations_clone(source_message_instance->message_annotations);
if (result->message_annotations == NULL)
{
message_destroy(result);
result = NULL;
}
}
if ((result != NULL) && (source_message_instance->properties != NULL))
{
/* Codes_SRS_MESSAGE_01_008: [If message properties exist on the source message they shall be cloned by using properties_clone.] */
result->properties = properties_clone(source_message_instance->properties);
if (result->properties == NULL)
{
message_destroy(result);
result = NULL;
}
}
if ((result != NULL) && (source_message_instance->application_properties != NULL))
{
/* Codes_SRS_MESSAGE_01_009: [If application properties exist on the source message they shall be cloned by using amqpvalue_clone.] */
result->application_properties = amqpvalue_clone(source_message_instance->application_properties);
if (result->application_properties == NULL)
{
message_destroy(result);
result = NULL;
}
}
if ((result != NULL) && (source_message_instance->footer != NULL))
{
/* Codes_SRS_MESSAGE_01_010: [If a footer exists on the source message it shall be cloned by using annotations_clone.] */
result->footer = amqpvalue_clone(source_message_instance->footer);
if (result->footer == NULL)
{
message_destroy(result);
result = NULL;
}
}
if ((result != NULL) && (source_message_instance->body_amqp_data_count > 0))
{
size_t i;
result->body_amqp_data_items = (BODY_AMQP_DATA*)amqpalloc_malloc(source_message_instance->body_amqp_data_count * sizeof(BODY_AMQP_DATA));
if (result->body_amqp_data_items == NULL)
{
message_destroy(result);
result = NULL;
}
else
{
for (i = 0; i < source_message_instance->body_amqp_data_count; i++)
{
result->body_amqp_data_items[i].body_data_section_length = source_message_instance->body_amqp_data_items[i].body_data_section_length;
/* Codes_SRS_MESSAGE_01_011: [If an AMQP data has been set as message body on the source message it shall be cloned by allocating memory for the binary payload.] */
result->body_amqp_data_items[i].body_data_section_bytes = amqpalloc_malloc(source_message_instance->body_amqp_data_items[i].body_data_section_length);
if (result->body_amqp_data_items[i].body_data_section_bytes == NULL)
{
break;
}
else
{
(void)memcpy(result->body_amqp_data_items[i].body_data_section_bytes, source_message_instance->body_amqp_data_items[i].body_data_section_bytes, result->body_amqp_data_items[i].body_data_section_length);
}
}
result->body_amqp_data_count = i;
if (i < source_message_instance->body_amqp_data_count)
{
message_destroy(result);
result = NULL;
}
}
}
if ((result != NULL) && (source_message_instance->body_amqp_sequence_count > 0))
{
size_t i;
result->body_amqp_sequence_items = (AMQP_VALUE*)amqpalloc_malloc(source_message_instance->body_amqp_sequence_count * sizeof(AMQP_VALUE));
if (result->body_amqp_sequence_items == NULL)
{
message_destroy(result);
result = NULL;
}
else
{
for (i = 0; i < source_message_instance->body_amqp_sequence_count; i++)
{
/* Codes_SRS_MESSAGE_01_011: [If an AMQP data has been set as message body on the source message it shall be cloned by allocating memory for the binary payload.] */
result->body_amqp_sequence_items[i] = amqpvalue_clone(source_message_instance->body_amqp_sequence_items[i]);
if (result->body_amqp_sequence_items[i] == NULL)
{
break;
}
}
result->body_amqp_sequence_count = i;
if (i < source_message_instance->body_amqp_sequence_count)
{
message_destroy(result);
result = NULL;
}
}
}
if ((result != NULL) && (source_message_instance->body_amqp_value != NULL))
{
result->body_amqp_value = amqpvalue_clone(source_message_instance->body_amqp_value);
if (result->body_amqp_value == NULL)
{
message_destroy(result);
result = NULL;
}
}
}
}
return result;
}
void message_destroy(MESSAGE_HANDLE message)
{
if (message != NULL)
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (message_instance->header != NULL)
{
header_destroy(message_instance->header);
}
if (message_instance->properties != NULL)
{
properties_destroy(message_instance->properties);
}
if (message_instance->application_properties != NULL)
{
application_properties_destroy(message_instance->application_properties);
}
if (message_instance->footer != NULL)
{
annotations_destroy(message_instance->footer);
}
if (message_instance->body_amqp_value != NULL)
{
amqpvalue_destroy(message_instance->body_amqp_value);
}
free_all_body_data_items(message_instance);
free_all_body_sequence_items(message_instance);
amqpalloc_free(message_instance);
}
}
int message_set_header(MESSAGE_HANDLE message, HEADER_HANDLE header)
{
int result;
if ((message == NULL) ||
(header == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
HEADER_HANDLE new_header;
new_header = header_clone(header);
if (new_header == NULL)
{
result = __LINE__;
}
else
{
if (message_instance->header != NULL)
{
header_destroy(message_instance->header);
}
message_instance->header = new_header;
result = 0;
}
}
return result;
}
int message_get_header(MESSAGE_HANDLE message, HEADER_HANDLE* header)
{
int result;
if ((message == NULL) ||
(header == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (message_instance->header == NULL)
{
*header = NULL;
result = 0;
}
else
{
*header = header_clone(message_instance->header);
if (*header == NULL)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
int message_set_delivery_annotations(MESSAGE_HANDLE message, annotations delivery_annotations)
{
int result;
if ((message == NULL) ||
(delivery_annotations == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
annotations new_delivery_annotations;
new_delivery_annotations = annotations_clone(delivery_annotations);
if (new_delivery_annotations == NULL)
{
result = __LINE__;
}
else
{
if (message_instance->delivery_annotations != NULL)
{
annotations_destroy(message_instance->delivery_annotations);
}
message_instance->delivery_annotations = new_delivery_annotations;
result = 0;
}
}
return result;
}
int message_get_delivery_annotations(MESSAGE_HANDLE message, annotations* delivery_annotations)
{
int result;
if ((message == NULL) ||
(delivery_annotations == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (message_instance->delivery_annotations == NULL)
{
*delivery_annotations = NULL;
result = 0;
}
else
{
*delivery_annotations = annotations_clone(message_instance->delivery_annotations);
if (*delivery_annotations == NULL)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
int message_set_message_annotations(MESSAGE_HANDLE message, annotations message_annotations)
{
int result;
if ((message == NULL) ||
(message_annotations == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
annotations new_message_annotations;
new_message_annotations = annotations_clone(message_annotations);
if (new_message_annotations == NULL)
{
result = __LINE__;
}
else
{
if (message_instance->message_annotations != NULL)
{
annotations_destroy(message_instance->message_annotations);
}
message_instance->message_annotations = new_message_annotations;
result = 0;
}
}
return result;
}
int message_get_message_annotations(MESSAGE_HANDLE message, annotations* message_annotations)
{
int result;
if ((message == NULL) ||
(message_annotations == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (message_instance->message_annotations == NULL)
{
*message_annotations = NULL;
result = 0;
}
else
{
*message_annotations = annotations_clone(message_instance->message_annotations);
if (*message_annotations == NULL)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
int message_set_properties(MESSAGE_HANDLE message, PROPERTIES_HANDLE properties)
{
int result;
if ((message == NULL) ||
(properties == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
PROPERTIES_HANDLE new_properties;
new_properties = properties_clone(properties);
if (new_properties == NULL)
{
result = __LINE__;
}
else
{
if (message_instance->properties != NULL)
{
properties_destroy(message_instance->properties);
}
message_instance->properties = new_properties;
result = 0;
}
}
return result;
}
int message_get_properties(MESSAGE_HANDLE message, PROPERTIES_HANDLE* properties)
{
int result;
if ((message == NULL) ||
(properties == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (message_instance->properties == NULL)
{
*properties = NULL;
result = 0;
}
else
{
*properties = properties_clone(message_instance->properties);
if (*properties == NULL)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
int message_set_application_properties(MESSAGE_HANDLE message, AMQP_VALUE application_properties)
{
int result;
if ((message == NULL) ||
(application_properties == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
AMQP_VALUE new_application_properties;
new_application_properties = application_properties_clone(application_properties);
if (new_application_properties == NULL)
{
result = __LINE__;
}
else
{
if (message_instance->application_properties != NULL)
{
amqpvalue_destroy(message_instance->application_properties);
}
message_instance->application_properties = new_application_properties;
result = 0;
}
}
return result;
}
int message_get_application_properties(MESSAGE_HANDLE message, AMQP_VALUE* application_properties)
{
int result;
if ((message == NULL) ||
(application_properties == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (message_instance->application_properties == NULL)
{
*application_properties = NULL;
result = 0;
}
else
{
*application_properties = application_properties_clone(message_instance->application_properties);
if (*application_properties == NULL)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
int message_set_footer(MESSAGE_HANDLE message, annotations footer)
{
int result;
if ((message == NULL) ||
(footer == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
AMQP_VALUE new_footer;
new_footer = annotations_clone(footer);
if (new_footer == NULL)
{
result = __LINE__;
}
else
{
if (message_instance->footer != NULL)
{
annotations_destroy(message_instance->footer);
}
message_instance->footer = new_footer;
result = 0;
}
}
return result;
}
int message_get_footer(MESSAGE_HANDLE message, annotations* footer)
{
int result;
if ((message == NULL) ||
(footer == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (message_instance->footer == NULL)
{
*footer = NULL;
result = 0;
}
else
{
*footer = annotations_clone(message_instance->footer);
if (*footer == NULL)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
int message_add_body_amqp_data(MESSAGE_HANDLE message, BINARY_DATA binary_data)
{
int result;
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if ((message == NULL) ||
(binary_data.bytes == NULL) ||
(binary_data.length == 0))
{
result = __LINE__;
}
else
{
BODY_AMQP_DATA* new_body_amqp_data_items = (BODY_AMQP_DATA*)amqpalloc_realloc(message_instance->body_amqp_data_items, sizeof(BODY_AMQP_DATA) * (message_instance->body_amqp_data_count + 1));
if (new_body_amqp_data_items == NULL)
{
result = __LINE__;
}
else
{
message_instance->body_amqp_data_items = new_body_amqp_data_items;
message_instance->body_amqp_data_items[message_instance->body_amqp_data_count].body_data_section_bytes = (unsigned char*)amqpalloc_malloc(binary_data.length);
if (message_instance->body_amqp_data_items[message_instance->body_amqp_data_count].body_data_section_bytes == NULL)
{
result = __LINE__;
}
else
{
message_instance->body_amqp_data_items[message_instance->body_amqp_data_count].body_data_section_length = binary_data.length;
(void)memcpy(message_instance->body_amqp_data_items[message_instance->body_amqp_data_count].body_data_section_bytes, binary_data.bytes, binary_data.length);
if (message_instance->body_amqp_value != NULL)
{
amqpvalue_destroy(message_instance->body_amqp_value);
message_instance->body_amqp_value = NULL;
}
free_all_body_sequence_items(message_instance);
message_instance->body_amqp_data_count++;
result = 0;
}
}
}
return result;
}
int message_get_body_amqp_data(MESSAGE_HANDLE message, size_t index, BINARY_DATA* binary_data)
{
int result;
if ((message == NULL) ||
(binary_data == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (index >= message_instance->body_amqp_data_count)
{
result = __LINE__;
}
else
{
binary_data->bytes = message_instance->body_amqp_data_items[index].body_data_section_bytes;
binary_data->length = message_instance->body_amqp_data_items[index].body_data_section_length;
result = 0;
}
}
return result;
}
int message_get_body_amqp_data_count(MESSAGE_HANDLE message, size_t* count)
{
int result;
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if ((message == NULL) ||
(count == NULL))
{
result = __LINE__;
}
else
{
*count = message_instance->body_amqp_data_count;
result = 0;
}
return result;
}
int message_add_body_amqp_sequence(MESSAGE_HANDLE message, AMQP_VALUE sequence_list)
{
int result;
size_t item_count;
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if ((message == NULL) ||
(sequence_list == NULL) ||
(amqpvalue_get_list_item_count(sequence_list, (uint32_t*)&item_count) != 0))
{
result = __LINE__;
}
else
{
AMQP_VALUE* new_body_amqp_sequence_items = (AMQP_VALUE*)amqpalloc_realloc(message_instance->body_amqp_sequence_items, sizeof(AMQP_VALUE) * (message_instance->body_amqp_sequence_count + 1));
if (new_body_amqp_sequence_items == NULL)
{
result = __LINE__;
}
else
{
message_instance->body_amqp_sequence_items = new_body_amqp_sequence_items;
message_instance->body_amqp_sequence_items[message_instance->body_amqp_sequence_count] = amqpvalue_clone(sequence_list);
if (message_instance->body_amqp_sequence_items[message_instance->body_amqp_sequence_count] == NULL)
{
result = __LINE__;
}
else
{
if (message_instance->body_amqp_value != NULL)
{
amqpvalue_destroy(message_instance->body_amqp_value);
message_instance->body_amqp_value = NULL;
}
free_all_body_data_items(message_instance);
message_instance->body_amqp_sequence_count++;
result = 0;
}
}
}
return result;
}
int message_get_body_amqp_sequence(MESSAGE_HANDLE message, size_t index, AMQP_VALUE* sequence_list)
{
int result;
if ((message == NULL) ||
(sequence_list == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (index >= message_instance->body_amqp_sequence_count)
{
result = __LINE__;
}
else
{
*sequence_list = amqpvalue_clone(message_instance->body_amqp_sequence_items[index]);
if (*sequence_list == NULL)
{
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
int message_get_body_amqp_sequence_count(MESSAGE_HANDLE message, size_t* count)
{
int result;
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if ((message == NULL) ||
(count == NULL))
{
result = __LINE__;
}
else
{
*count = message_instance->body_amqp_sequence_count;
result = 0;
}
return result;
}
int message_set_body_amqp_value(MESSAGE_HANDLE message, AMQP_VALUE body_amqp_value)
{
int result;
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if ((message == NULL) ||
(body_amqp_value == NULL))
{
result = __LINE__;
}
else
{
message_instance->body_amqp_value = amqpvalue_clone(body_amqp_value);
free_all_body_data_items(message_instance);
free_all_body_sequence_items(message_instance);
result = 0;
}
return result;
}
int message_get_inplace_body_amqp_value(MESSAGE_HANDLE message, AMQP_VALUE* body_amqp_value)
{
int result;
if ((message == NULL) ||
(body_amqp_value == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
*body_amqp_value = message_instance->body_amqp_value;
result = 0;
}
return result;
}
int message_get_body_type(MESSAGE_HANDLE message, MESSAGE_BODY_TYPE* body_type)
{
int result;
if ((message == NULL) ||
(body_type == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_INSTANCE* message_instance = (MESSAGE_INSTANCE*)message;
if (message_instance->body_amqp_value != NULL)
{
*body_type = MESSAGE_BODY_TYPE_VALUE;
}
else if (message_instance->body_amqp_data_count > 0)
{
*body_type = MESSAGE_BODY_TYPE_DATA;
}
else if (message_instance->body_amqp_sequence_count > 0)
{
*body_type = MESSAGE_BODY_TYPE_SEQUENCE;
}
else
{
*body_type = MESSAGE_BODY_TYPE_NONE;
}
result = 0;
}
return result;
}

324
src/message_receiver.c Normal file
Просмотреть файл

@ -0,0 +1,324 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include "message_receiver.h"
#include "amqpalloc.h"
#include "amqpvalue.h"
#include "amqp_definitions.h"
typedef struct MESSAGE_RECEIVER_INSTANCE_TAG
{
LINK_HANDLE link;
ON_MESSAGE_RECEIVED on_message_received;
ON_MESSAGE_RECEIVER_STATE_CHANGED on_message_receiver_state_changed;
MESSAGE_RECEIVER_STATE message_receiver_state;
const void* on_message_receiver_state_changed_context;
const void* callback_context;
MESSAGE_HANDLE decoded_message;
bool decode_error;
} MESSAGE_RECEIVER_INSTANCE;
static void set_message_receiver_state(MESSAGE_RECEIVER_INSTANCE* message_receiver_instance, MESSAGE_RECEIVER_STATE new_state)
{
MESSAGE_RECEIVER_STATE previous_state = message_receiver_instance->message_receiver_state;
message_receiver_instance->message_receiver_state = new_state;
if (message_receiver_instance->on_message_receiver_state_changed != NULL)
{
message_receiver_instance->on_message_receiver_state_changed(message_receiver_instance->on_message_receiver_state_changed_context, new_state, previous_state);
}
}
static void decode_message_value_callback(void* context, AMQP_VALUE decoded_value)
{
MESSAGE_RECEIVER_INSTANCE* message_receiver_instance = (MESSAGE_RECEIVER_INSTANCE*)context;
MESSAGE_HANDLE decoded_message = message_receiver_instance->decoded_message;
AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(decoded_value);
if (is_application_properties_type_by_descriptor(descriptor))
{
if (message_set_application_properties(decoded_message, decoded_value) != 0)
{
message_receiver_instance->decode_error = true;
}
}
else if (is_properties_type_by_descriptor(descriptor))
{
PROPERTIES_HANDLE properties;
if (amqpvalue_get_properties(decoded_value, &properties) != 0)
{
message_receiver_instance->decode_error = true;
}
else
{
if (message_set_properties(decoded_message, properties) != 0)
{
message_receiver_instance->decode_error = true;
}
properties_destroy(properties);
}
}
else if (is_delivery_annotations_type_by_descriptor(descriptor))
{
annotations delivery_annotations = amqpvalue_get_inplace_described_value(decoded_value);
if ((delivery_annotations == NULL) ||
(message_set_delivery_annotations(decoded_message, delivery_annotations) != 0))
{
message_receiver_instance->decode_error = true;
}
}
else if (is_message_annotations_type_by_descriptor(descriptor))
{
annotations message_annotations = amqpvalue_get_inplace_described_value(decoded_value);
if ((message_annotations == NULL) ||
(message_set_message_annotations(decoded_message, message_annotations) != 0))
{
message_receiver_instance->decode_error = true;
}
}
else if (is_header_type_by_descriptor(descriptor))
{
HEADER_HANDLE header;
if (amqpvalue_get_header(decoded_value, &header) != 0)
{
message_receiver_instance->decode_error = true;
}
else
{
if (message_set_header(decoded_message, header) != 0)
{
message_receiver_instance->decode_error = true;
}
header_destroy(header);
}
}
else if (is_footer_type_by_descriptor(descriptor))
{
annotations footer = amqpvalue_get_inplace_described_value(decoded_value);
if ((footer == NULL) ||
(message_set_footer(decoded_message, footer) != 0))
{
message_receiver_instance->decode_error = true;
}
}
else if (is_amqp_value_type_by_descriptor(descriptor))
{
MESSAGE_BODY_TYPE body_type;
message_get_body_type(decoded_message, &body_type);
if (body_type != MESSAGE_BODY_TYPE_NONE)
{
message_receiver_instance->decode_error = true;
}
else
{
AMQP_VALUE body_amqp_value = amqpvalue_get_inplace_described_value(decoded_value);
if ((body_amqp_value == NULL) ||
(message_set_body_amqp_value(decoded_message, body_amqp_value) != 0))
{
message_receiver_instance->decode_error = true;
}
}
}
else if (is_data_type_by_descriptor(descriptor))
{
MESSAGE_BODY_TYPE body_type;
message_get_body_type(decoded_message, &body_type);
if ((body_type != MESSAGE_BODY_TYPE_NONE) &&
(body_type != MESSAGE_BODY_TYPE_DATA))
{
message_receiver_instance->decode_error = true;
}
else
{
AMQP_VALUE body_data_value = amqpvalue_get_inplace_described_value(decoded_value);
data data_value;
if ((body_data_value == NULL) ||
(amqpvalue_get_data(body_data_value, &data_value) != 0))
{
message_receiver_instance->decode_error = true;
}
else
{
BINARY_DATA binary_data = { data_value.bytes, data_value.length };
if (message_add_body_amqp_data(decoded_message, binary_data) != 0)
{
message_receiver_instance->decode_error = true;
}
}
}
}
}
static AMQP_VALUE on_transfer_received(void* context, TRANSFER_HANDLE transfer, uint32_t payload_size, const unsigned char* payload_bytes)
{
AMQP_VALUE result = NULL;
MESSAGE_RECEIVER_INSTANCE* message_receiver_instance = (MESSAGE_RECEIVER_INSTANCE*)context;
if (message_receiver_instance->on_message_received != NULL)
{
MESSAGE_HANDLE message = message_create();
if (message == NULL)
{
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_ERROR);
}
else
{
message_receiver_instance->decoded_message;
AMQPVALUE_DECODER_HANDLE amqpvalue_decoder = amqpvalue_decoder_create(decode_message_value_callback, message_receiver_instance);
if (amqpvalue_decoder == NULL)
{
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_ERROR);
}
else
{
message_receiver_instance->decoded_message = message;
message_receiver_instance->decode_error = false;
if (amqpvalue_decode_bytes(amqpvalue_decoder, payload_bytes, payload_size) != 0)
{
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_ERROR);
}
else
{
if (message_receiver_instance->decode_error)
{
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_ERROR);
}
else
{
result = message_receiver_instance->on_message_received(message_receiver_instance->callback_context, message);
}
}
amqpvalue_decoder_destroy(amqpvalue_decoder);
}
message_destroy(message);
}
}
return result;
}
static void on_link_state_changed(void* context, LINK_STATE new_link_state, LINK_STATE previous_link_state)
{
MESSAGE_RECEIVER_INSTANCE* message_receiver_instance = (MESSAGE_RECEIVER_INSTANCE*)context;
switch (new_link_state)
{
case LINK_STATE_ATTACHED:
if (message_receiver_instance->message_receiver_state == MESSAGE_RECEIVER_STATE_OPENING)
{
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_OPEN);
}
break;
case LINK_STATE_DETACHED:
if ((message_receiver_instance->message_receiver_state == MESSAGE_RECEIVER_STATE_OPEN) ||
(message_receiver_instance->message_receiver_state == MESSAGE_RECEIVER_STATE_CLOSING))
{
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_IDLE);
}
break;
}
}
MESSAGE_RECEIVER_HANDLE messagereceiver_create(LINK_HANDLE link, ON_MESSAGE_RECEIVER_STATE_CHANGED on_message_receiver_state_changed, void* context)
{
MESSAGE_RECEIVER_INSTANCE* result = (MESSAGE_RECEIVER_INSTANCE*)amqpalloc_malloc(sizeof(MESSAGE_RECEIVER_INSTANCE));
if (result != NULL)
{
result->link = link;
result->on_message_receiver_state_changed = on_message_receiver_state_changed;
result->on_message_receiver_state_changed_context = context;
result->message_receiver_state = MESSAGE_RECEIVER_STATE_IDLE;
}
return result;
}
void messagereceiver_destroy(MESSAGE_RECEIVER_HANDLE message_receiver)
{
if (message_receiver != NULL)
{
amqpalloc_free(message_receiver);
}
}
int messagereceiver_open(MESSAGE_RECEIVER_HANDLE message_receiver, ON_MESSAGE_RECEIVED on_message_received, const void* callback_context)
{
int result;
if (message_receiver == NULL)
{
result = __LINE__;
}
else
{
MESSAGE_RECEIVER_INSTANCE* message_receiver_instance = (MESSAGE_RECEIVER_INSTANCE*)message_receiver;
if (message_receiver_instance->message_receiver_state == MESSAGE_RECEIVER_STATE_IDLE)
{
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_OPENING);
if (link_attach(message_receiver_instance->link, on_transfer_received, on_link_state_changed, NULL, message_receiver_instance) != 0)
{
result = __LINE__;
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_ERROR);
}
else
{
message_receiver_instance->on_message_received = on_message_received;
message_receiver_instance->callback_context = callback_context;
result = 0;
}
}
else
{
result = 0;
}
}
return result;
}
int messagereceiver_close(MESSAGE_RECEIVER_HANDLE message_receiver)
{
int result;
if (message_receiver == NULL)
{
result = __LINE__;
}
else
{
MESSAGE_RECEIVER_INSTANCE* message_receiver_instance = (MESSAGE_RECEIVER_INSTANCE*)message_receiver;
if ((message_receiver_instance->message_receiver_state == MESSAGE_RECEIVER_STATE_OPENING) ||
(message_receiver_instance->message_receiver_state == MESSAGE_RECEIVER_STATE_OPEN))
{
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_CLOSING);
if (link_detach(message_receiver_instance->link) != 0)
{
result = __LINE__;
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_ERROR);
}
else
{
set_message_receiver_state(message_receiver_instance, MESSAGE_RECEIVER_STATE_IDLE);
result = 0;
}
}
else
{
result = 0;
}
}
return result;
}

636
src/message_sender.c Normal file
Просмотреть файл

@ -0,0 +1,636 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <string.h>
#include "message_sender.h"
#include "amqpalloc.h"
#include "logger.h"
#include "amqpvalue_to_string.h"
#include "logger.h"
typedef enum MESSAGE_SEND_STATE_TAG
{
MESSAGE_SEND_STATE_NOT_SENT,
MESSAGE_SEND_STATE_PENDING
} MESSAGE_SEND_STATE;
typedef enum SEND_ONE_MESSAGE_RESULT_TAG
{
SEND_ONE_MESSAGE_OK,
SEND_ONE_MESSAGE_ERROR,
SEND_ONE_MESSAGE_BUSY
} SEND_ONE_MESSAGE_RESULT;
typedef struct MESSAGE_WITH_CALLBACK_TAG
{
MESSAGE_HANDLE message;
ON_MESSAGE_SEND_COMPLETE on_message_send_complete;
const void* context;
MESSAGE_SENDER_HANDLE message_sender;
MESSAGE_SEND_STATE message_send_state;
} MESSAGE_WITH_CALLBACK;
typedef struct MESSAGE_SENDER_INSTANCE_TAG
{
LINK_HANDLE link;
size_t message_count;
MESSAGE_WITH_CALLBACK** messages;
MESSAGE_SENDER_STATE message_sender_state;
ON_MESSAGE_SENDER_STATE_CHANGED on_message_sender_state_changed;
void* on_message_sender_state_changed_context;
LOGGER_LOG logger_log;
} MESSAGE_SENDER_INSTANCE;
static void remove_pending_message_by_index(MESSAGE_SENDER_INSTANCE* message_sender_instance, size_t index)
{
MESSAGE_WITH_CALLBACK** new_messages;
if (message_sender_instance->messages[index]->message != NULL)
{
message_destroy(message_sender_instance->messages[index]->message);
message_sender_instance->messages[index]->message = NULL;
}
amqpalloc_free(message_sender_instance->messages[index]);
if (message_sender_instance->message_count - index > 1)
{
(void)memmove(&message_sender_instance->messages[index], &message_sender_instance->messages[index + 1], sizeof(MESSAGE_WITH_CALLBACK*) * (message_sender_instance->message_count - index - 1));
}
message_sender_instance->message_count--;
if (message_sender_instance->message_count > 0)
{
new_messages = (MESSAGE_WITH_CALLBACK**)amqpalloc_realloc(message_sender_instance->messages, sizeof(MESSAGE_WITH_CALLBACK*) * (message_sender_instance->message_count));
if (new_messages != NULL)
{
message_sender_instance->messages = new_messages;
}
}
else
{
amqpalloc_free(message_sender_instance->messages);
message_sender_instance->messages = NULL;
}
}
static void remove_pending_message(MESSAGE_SENDER_INSTANCE* message_sender_instance, MESSAGE_WITH_CALLBACK* message_with_callback)
{
size_t i;
for (i = 0; i < message_sender_instance->message_count; i++)
{
if (message_sender_instance->messages[i] == message_with_callback)
{
remove_pending_message_by_index(message_sender_instance, i);
break;
}
}
}
static void on_delivery_settled(void* context, delivery_number delivery_no)
{
MESSAGE_WITH_CALLBACK* message_with_callback = (MESSAGE_WITH_CALLBACK*)context;
MESSAGE_SENDER_INSTANCE* message_sender_instance = (MESSAGE_SENDER_INSTANCE*)message_with_callback->message_sender;
if (message_with_callback->on_message_send_complete != NULL)
{
message_with_callback->on_message_send_complete(message_with_callback->context, MESSAGE_SEND_OK);
}
remove_pending_message(message_sender_instance, message_with_callback);
}
static int encode_bytes(void* context, const unsigned char* bytes, size_t length)
{
PAYLOAD* payload = (PAYLOAD*)context;
(void)memcpy((unsigned char*)payload->bytes + payload->length, bytes, length);
payload->length += length;
return 0;
}
static void log_message_chunk(MESSAGE_SENDER_INSTANCE* message_sender_instance, const char* name, AMQP_VALUE value)
{
if (message_sender_instance->logger_log != NULL)
{
char* value_as_string = NULL;
LOG(message_sender_instance->logger_log, 0, "%s", name);
LOG(message_sender_instance->logger_log, 0, "%s", (value_as_string = amqpvalue_to_string(value)));
if (value_as_string != NULL)
{
amqpalloc_free(value_as_string);
}
}
}
static SEND_ONE_MESSAGE_RESULT send_one_message(MESSAGE_SENDER_INSTANCE* message_sender_instance, MESSAGE_WITH_CALLBACK* message_with_callback, MESSAGE_HANDLE message)
{
SEND_ONE_MESSAGE_RESULT result;
size_t encoded_size;
size_t total_encoded_size = 0;
MESSAGE_BODY_TYPE message_body_type;
if (message_get_body_type(message, &message_body_type) != 0)
{
result = SEND_ONE_MESSAGE_ERROR;
}
else
{
// header
HEADER_HANDLE header;
AMQP_VALUE header_amqp_value;
PROPERTIES_HANDLE properties;
AMQP_VALUE properties_amqp_value;
AMQP_VALUE application_properties;
AMQP_VALUE application_properties_value;
AMQP_VALUE body_amqp_data = NULL;
AMQP_VALUE body_amqp_value = NULL;
message_get_header(message, &header);
header_amqp_value = amqpvalue_create_header(header);
if (header != NULL)
{
amqpvalue_get_encoded_size(header_amqp_value, &encoded_size);
total_encoded_size += encoded_size;
}
// properties
message_get_properties(message, &properties);
properties_amqp_value = amqpvalue_create_properties(properties);
if (properties != NULL)
{
amqpvalue_get_encoded_size(properties_amqp_value, &encoded_size);
total_encoded_size += encoded_size;
}
// application properties
message_get_application_properties(message, &application_properties);
application_properties_value = amqpvalue_create_application_properties(application_properties);
if (application_properties != NULL)
{
amqpvalue_get_encoded_size(application_properties_value, &encoded_size);
total_encoded_size += encoded_size;
}
result = SEND_ONE_MESSAGE_OK;
// body - amqp data
switch (message_body_type)
{
default:
result = SEND_ONE_MESSAGE_ERROR;
break;
case MESSAGE_BODY_TYPE_VALUE:
{
AMQP_VALUE message_body_amqp_value;
if (message_get_inplace_body_amqp_value(message, &message_body_amqp_value) != 0)
{
result = SEND_ONE_MESSAGE_ERROR;
}
else
{
body_amqp_value = amqpvalue_create_amqp_value(message_body_amqp_value);
if ((body_amqp_value == NULL) ||
(amqpvalue_get_encoded_size(body_amqp_value, &encoded_size) != 0))
{
result = SEND_ONE_MESSAGE_ERROR;
}
else
{
total_encoded_size += encoded_size;
}
}
break;
}
case MESSAGE_BODY_TYPE_DATA:
{
BINARY_DATA binary_data;
if (message_get_body_amqp_data(message, 0, &binary_data) != 0)
{
result = SEND_ONE_MESSAGE_ERROR;
}
else
{
amqp_binary binary_value = { binary_data.bytes, binary_data.length };
body_amqp_data = amqpvalue_create_data(binary_value);
if ((body_amqp_data == NULL) ||
(amqpvalue_get_encoded_size(body_amqp_data, &encoded_size) != 0))
{
result = SEND_ONE_MESSAGE_ERROR;
}
else
{
total_encoded_size += encoded_size;
}
}
break;
}
}
if (result == 0)
{
void* data_bytes = amqpalloc_malloc(total_encoded_size);
PAYLOAD payload = { data_bytes, 0 };
result = SEND_ONE_MESSAGE_OK;
if (header != NULL)
{
if (amqpvalue_encode(header_amqp_value, encode_bytes, &payload) != 0)
{
result = SEND_ONE_MESSAGE_ERROR;
}
log_message_chunk(message_sender_instance, "Header:", header_amqp_value);
}
if ((result == SEND_ONE_MESSAGE_OK) && (properties != NULL))
{
if (amqpvalue_encode(properties_amqp_value, encode_bytes, &payload) != 0)
{
result = SEND_ONE_MESSAGE_ERROR;
}
log_message_chunk(message_sender_instance, "Properties:", properties_amqp_value);
}
if ((result == SEND_ONE_MESSAGE_OK) && (application_properties != NULL))
{
if (amqpvalue_encode(application_properties_value, encode_bytes, &payload) != 0)
{
result = SEND_ONE_MESSAGE_ERROR;
}
log_message_chunk(message_sender_instance, "Application properties:", application_properties_value);
}
if (result == SEND_ONE_MESSAGE_OK)
{
switch (message_body_type)
{
case MESSAGE_BODY_TYPE_VALUE:
{
if (amqpvalue_encode(body_amqp_value, encode_bytes, &payload) != 0)
{
result = SEND_ONE_MESSAGE_ERROR;
}
log_message_chunk(message_sender_instance, "Body - amqp value:", body_amqp_value);
break;
}
case MESSAGE_BODY_TYPE_DATA:
{
if (amqpvalue_encode(body_amqp_data, encode_bytes, &payload) != 0)
{
result = SEND_ONE_MESSAGE_ERROR;
}
log_message_chunk(message_sender_instance, "Body - amqp data:", body_amqp_data);
break;
}
}
}
if (result == SEND_ONE_MESSAGE_OK)
{
message_with_callback->message_send_state = MESSAGE_SEND_STATE_PENDING;
switch (link_transfer(message_sender_instance->link, &payload, 1, on_delivery_settled, message_with_callback))
{
default:
case LINK_TRANSFER_ERROR:
if (message_with_callback->on_message_send_complete != NULL)
{
message_with_callback->on_message_send_complete(message_with_callback->context, MESSAGE_SEND_ERROR);
}
result = SEND_ONE_MESSAGE_ERROR;
break;
case LINK_TRANSFER_BUSY:
message_with_callback->message_send_state = MESSAGE_SEND_STATE_NOT_SENT;
result = SEND_ONE_MESSAGE_BUSY;
break;
case LINK_TRANSFER_OK:
result = SEND_ONE_MESSAGE_OK;
break;
}
}
amqpalloc_free(data_bytes);
if (body_amqp_data != NULL)
{
amqpvalue_destroy(body_amqp_data);
}
if (body_amqp_value != NULL)
{
amqpvalue_destroy(body_amqp_value);
}
amqpvalue_destroy(application_properties);
amqpvalue_destroy(application_properties_value);
amqpvalue_destroy(properties_amqp_value);
properties_destroy(properties);
}
}
return result;
}
static void send_all_pending_messages(MESSAGE_SENDER_INSTANCE* message_sender_instance)
{
size_t i;
for (i = 0; i < message_sender_instance->message_count; i++)
{
if (message_sender_instance->messages[i]->message_send_state == MESSAGE_SEND_STATE_NOT_SENT)
{
switch (send_one_message(message_sender_instance, message_sender_instance->messages[i], message_sender_instance->messages[i]->message))
{
default:
case SEND_ONE_MESSAGE_ERROR:
{
ON_MESSAGE_SEND_COMPLETE on_message_send_complete = message_sender_instance->messages[i]->on_message_send_complete;
const void* context = message_sender_instance->messages[i]->context;
remove_pending_message_by_index(message_sender_instance, i);
on_message_send_complete(context, MESSAGE_SEND_ERROR);
i = message_sender_instance->message_count;
break;
}
case SEND_ONE_MESSAGE_BUSY:
i = message_sender_instance->message_count + 1;
break;
case SEND_ONE_MESSAGE_OK:
break;
}
i--;
}
}
}
static void set_message_sender_state(MESSAGE_SENDER_INSTANCE* message_sender_instance, MESSAGE_SENDER_STATE new_state)
{
MESSAGE_SENDER_STATE previous_state = message_sender_instance->message_sender_state;
message_sender_instance->message_sender_state = new_state;
if (message_sender_instance->on_message_sender_state_changed != NULL)
{
message_sender_instance->on_message_sender_state_changed(message_sender_instance->on_message_sender_state_changed_context, new_state, previous_state);
}
}
static void on_link_state_changed(void* context, LINK_STATE new_link_state, LINK_STATE previous_link_state)
{
MESSAGE_SENDER_INSTANCE* message_sender_instance = (MESSAGE_SENDER_INSTANCE*)context;
switch (new_link_state)
{
case LINK_STATE_ATTACHED:
if (message_sender_instance->message_sender_state == MESSAGE_SENDER_STATE_OPENING)
{
set_message_sender_state(message_sender_instance, MESSAGE_SENDER_STATE_OPEN);
}
break;
case LINK_STATE_DETACHED:
if ((message_sender_instance->message_sender_state == MESSAGE_SENDER_STATE_OPEN) ||
(message_sender_instance->message_sender_state == MESSAGE_SENDER_STATE_CLOSING))
{
set_message_sender_state(message_sender_instance, MESSAGE_SENDER_STATE_IDLE);
}
break;
}
}
static void on_link_flow_on(void* context)
{
MESSAGE_SENDER_INSTANCE* message_sender_instance = (MESSAGE_SENDER_INSTANCE*)context;
send_all_pending_messages(message_sender_instance);
}
MESSAGE_SENDER_HANDLE messagesender_create(LINK_HANDLE link, ON_MESSAGE_SENDER_STATE_CHANGED on_message_sender_state_changed, void* context, LOGGER_LOG logger_log)
{
MESSAGE_SENDER_INSTANCE* result = amqpalloc_malloc(sizeof(MESSAGE_SENDER_INSTANCE));
if (result != NULL)
{
result->messages = NULL;
result->message_count = 0;
result->link = link;
result->on_message_sender_state_changed = on_message_sender_state_changed;
result->on_message_sender_state_changed_context = context;
result->message_sender_state = MESSAGE_SENDER_STATE_IDLE;
result->logger_log = logger_log;
}
return result;
}
void messagesender_destroy(MESSAGE_SENDER_HANDLE message_sender)
{
if (message_sender != NULL)
{
MESSAGE_SENDER_INSTANCE* message_sender_instance = (MESSAGE_SENDER_INSTANCE*)message_sender;
size_t i;
messagesender_close(message_sender_instance);
for (i = 0; i < message_sender_instance->message_count; i++)
{
if (message_sender_instance->messages[i]->on_message_send_complete != NULL)
{
message_sender_instance->messages[i]->on_message_send_complete(message_sender_instance->messages[i]->context, MESSAGE_SEND_ERROR);
}
message_destroy(message_sender_instance->messages[i]->message);
amqpalloc_free(message_sender_instance->messages[i]);
}
if (message_sender_instance->messages != NULL)
{
amqpalloc_free(message_sender_instance->messages);
}
amqpalloc_free(message_sender);
}
}
int messagesender_open(MESSAGE_SENDER_HANDLE message_sender)
{
int result;
if (message_sender == NULL)
{
result = __LINE__;
}
else
{
MESSAGE_SENDER_INSTANCE* message_sender_instance = (MESSAGE_SENDER_INSTANCE*)message_sender;
if (message_sender_instance->message_sender_state == MESSAGE_SENDER_STATE_IDLE)
{
set_message_sender_state(message_sender_instance, MESSAGE_SENDER_STATE_OPENING);
if (link_attach(message_sender_instance->link, NULL, on_link_state_changed, on_link_flow_on, message_sender_instance) != 0)
{
result = __LINE__;
set_message_sender_state(message_sender_instance, MESSAGE_SENDER_STATE_ERROR);
}
else
{
result = 0;
}
}
else
{
result = 0;
}
}
return result;
}
int messagesender_close(MESSAGE_SENDER_HANDLE message_sender)
{
int result;
if (message_sender == NULL)
{
result = __LINE__;
}
else
{
MESSAGE_SENDER_INSTANCE* message_sender_instance = (MESSAGE_SENDER_INSTANCE*)message_sender;
if ((message_sender_instance->message_sender_state == MESSAGE_SENDER_STATE_OPENING) ||
(message_sender_instance->message_sender_state == MESSAGE_SENDER_STATE_OPEN))
{
set_message_sender_state(message_sender_instance, MESSAGE_SENDER_STATE_CLOSING);
if (link_detach(message_sender_instance->link) != 0)
{
result = __LINE__;
set_message_sender_state(message_sender_instance, MESSAGE_SENDER_STATE_ERROR);
}
else
{
set_message_sender_state(message_sender_instance, MESSAGE_SENDER_STATE_IDLE);
result = 0;
}
}
else
{
result = 0;
}
}
return result;
}
int messagesender_send(MESSAGE_SENDER_HANDLE message_sender, MESSAGE_HANDLE message, ON_MESSAGE_SEND_COMPLETE on_message_send_complete, const void* callback_context)
{
int result;
if ((message_sender == NULL) ||
(message == NULL))
{
result = __LINE__;
}
else
{
MESSAGE_SENDER_INSTANCE* message_sender_instance = (MESSAGE_SENDER_INSTANCE*)message_sender;
if (message_sender_instance->message_sender_state == MESSAGE_SENDER_STATE_ERROR)
{
result = __LINE__;
}
else
{
MESSAGE_WITH_CALLBACK* message_with_callback = (MESSAGE_WITH_CALLBACK*)amqpalloc_malloc(sizeof(MESSAGE_WITH_CALLBACK));
if (message_with_callback == NULL)
{
result = __LINE__;
}
else
{
MESSAGE_WITH_CALLBACK** new_messages = (MESSAGE_WITH_CALLBACK**)amqpalloc_realloc(message_sender_instance->messages, sizeof(MESSAGE_WITH_CALLBACK*) * (message_sender_instance->message_count + 1));
if (new_messages == NULL)
{
amqpalloc_free(message_with_callback);
result = __LINE__;
}
else
{
result = 0;
message_sender_instance->messages = new_messages;
if (message_sender_instance->message_sender_state != MESSAGE_SENDER_STATE_OPEN)
{
message_with_callback->message = message_clone(message);
if (message_with_callback->message == NULL)
{
amqpalloc_free(message_with_callback);
result = __LINE__;
}
message_with_callback->message_send_state = MESSAGE_SEND_STATE_NOT_SENT;
}
else
{
message_with_callback->message = NULL;
message_with_callback->message_send_state = MESSAGE_SEND_STATE_PENDING;
}
if (result == 0)
{
message_with_callback->on_message_send_complete = on_message_send_complete;
message_with_callback->context = callback_context;
message_with_callback->message_sender = message_sender_instance;
message_sender_instance->messages[message_sender_instance->message_count] = message_with_callback;
message_sender_instance->message_count++;
if (message_sender_instance->message_sender_state == MESSAGE_SENDER_STATE_OPEN)
{
switch (send_one_message(message_sender_instance, message_with_callback, message))
{
default:
case SEND_ONE_MESSAGE_ERROR:
remove_pending_message_by_index(message_sender_instance, message_sender_instance->message_count - 1);
result = __LINE__;
break;
case SEND_ONE_MESSAGE_BUSY:
message_with_callback->message = message_clone(message);
if (message_with_callback->message == NULL)
{
amqpalloc_free(message_with_callback);
result = __LINE__;
}
else
{
message_with_callback->message_send_state = MESSAGE_SEND_STATE_NOT_SENT;
result = 0;
}
break;
case SEND_ONE_MESSAGE_OK:
result = 0;
break;
}
}
}
}
}
}
}
return result;
}

212
src/messaging.c Normal file
Просмотреть файл

@ -0,0 +1,212 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdbool.h>
#include "amqpvalue.h"
#include "amqp_definitions.h"
AMQP_VALUE messaging_create_source(const char* address)
{
AMQP_VALUE result;
SOURCE_HANDLE source = source_create();
if (source == NULL)
{
result = NULL;
}
else
{
AMQP_VALUE address_value = amqpvalue_create_string(address);
if (address_value == NULL)
{
result = NULL;
}
else
{
if (source_set_address(source, address_value) != 0)
{
result = NULL;
}
else
{
result = amqpvalue_create_source(source);
}
amqpvalue_destroy(address_value);
}
source_destroy(source);
}
return result;
}
AMQP_VALUE messaging_create_target(const char* address)
{
AMQP_VALUE result;
TARGET_HANDLE target = target_create();
if (target == NULL)
{
result = NULL;
}
else
{
AMQP_VALUE address_value = amqpvalue_create_string(address);
if (address_value == NULL)
{
result = NULL;
}
else
{
if (target_set_address(target, address_value) != 0)
{
result = NULL;
}
else
{
result = amqpvalue_create_target(target);
}
amqpvalue_destroy(address_value);
}
target_destroy(target);
}
return result;
}
AMQP_VALUE messaging_delivery_received(uint32_t section_number, uint64_t section_offset)
{
AMQP_VALUE result;
RECEIVED_HANDLE received = received_create(section_number, section_offset);
if (received == NULL)
{
result = NULL;
}
else
{
result = amqpvalue_create_received(received);
received_destroy(received);
}
return result;
}
AMQP_VALUE messaging_delivery_accepted(void)
{
AMQP_VALUE result;
ACCEPTED_HANDLE accepted = accepted_create();
if (accepted == NULL)
{
result = NULL;
}
else
{
result = amqpvalue_create_accepted(accepted);
accepted_destroy(accepted);
}
return result;
}
AMQP_VALUE messaging_delivery_rejected(const char* error_condition, const char* error_description)
{
AMQP_VALUE result;
REJECTED_HANDLE rejected = rejected_create();
if (rejected == NULL)
{
result = NULL;
}
else
{
ERROR_HANDLE error_handle = NULL;
bool error_constructing = false;
if (error_condition != NULL)
{
error_handle = error_create(error_condition);
if (error_handle == NULL)
{
error_constructing = true;
}
else
{
if ((error_description != NULL) &&
(error_set_description(error_handle, error_description) != 0))
{
error_constructing = true;
}
else
{
if (rejected_set_error(rejected, error_handle) != 0)
{
error_constructing = true;
}
}
error_destroy(error_handle);
}
}
if (error_constructing)
{
result = NULL;
}
else
{
result = amqpvalue_create_rejected(rejected);
}
rejected_destroy(rejected);
}
return result;
}
AMQP_VALUE messaging_delivery_released(void)
{
AMQP_VALUE result;
RELEASED_HANDLE released = released_create();
if (released == NULL)
{
result = NULL;
}
else
{
result = amqpvalue_create_released(released);
released_destroy(released);
}
return result;
}
AMQP_VALUE messaging_delivery_modified(bool delivery_failed, bool undeliverable_here, fields message_annotations)
{
AMQP_VALUE result;
MODIFIED_HANDLE modified = modified_create();
if (modified == NULL)
{
result = NULL;
}
else
{
if ((modified_set_delivery_failed(modified, delivery_failed) != 0) ||
(modified_set_undeliverable_here(modified, undeliverable_here) != 0) ||
((message_annotations != NULL) && (modified_set_message_annotations(modified, message_annotations) != 0)))
{
result = NULL;
}
else
{
result = amqpvalue_create_modified(modified);
}
modified_destroy(modified);
}
return result;
}

31
src/platform_win32.c Normal file
Просмотреть файл

@ -0,0 +1,31 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include "platform.h"
#include "winsock2.h"
int platform_init(void)
{
int result;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
result = __LINE__;
}
else
{
result = 0;
}
return result;
}
void platform_deinit(void)
{
(void)WSACleanup();
}

91
src/sasl_anonymous.c Normal file
Просмотреть файл

@ -0,0 +1,91 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <string.h>
#include "sasl_anonymous.h"
#include "amqpalloc.h"
#include "logger.h"
typedef struct SASL_ANONYMOUS_INSTANCE_TAG
{
unsigned char dummy : 1;
} SASL_ANONYMOUS_INSTANCE;
static const SASL_MECHANISM_INTERFACE_DESCRIPTION saslanonymous_interface =
{
saslanonymous_create,
saslanonymous_destroy,
saslanonymous_get_init_bytes,
saslanonymous_get_mechanism_name
};
/* Codes_SRS_SASL_ANONYMOUS_01_001: [saslanonymous_create shall return on success a non-NULL handle to a new SASL anonymous mechanism.] */
CONCRETE_SASL_MECHANISM_HANDLE saslanonymous_create(void* config)
{
/* Codes_SRS_SASL_ANONYMOUS_01_003: [Since this is the ANONYMOUS SASL mechanism, config shall be ignored.] */
(void)config;
/* Codes_SRS_SASL_ANONYMOUS_01_002: [If allocating the memory needed for the saslanonymous instance fails then saslanonymous_create shall return NULL.] */
return amqpalloc_malloc(sizeof(SASL_ANONYMOUS_INSTANCE));
}
void saslanonymous_destroy(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle)
{
/* Codes_SRS_SASL_ANONYMOUS_01_005: [If the argument concrete_sasl_mechanism is NULL, saslannymous_destroy shall do nothing.] */
if (sasl_mechanism_concrete_handle != NULL)
{
/* Codes_SRS_SASL_ANONYMOUS_01_004: [saslannymous_destroy shall free all resources associated with the SASL mechanism.] */
amqpalloc_free(sasl_mechanism_concrete_handle);
}
}
int saslanonymous_get_init_bytes(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle, SASL_MECHANISM_BYTES* init_bytes)
{
int result;
/* Codes_SRS_SASL_ANONYMOUS_01_007: [If the any argument is NULL, saslanonymous_get_init_bytes shall return a non-zero value.] */
if ((sasl_mechanism_concrete_handle == NULL) ||
(init_bytes == NULL))
{
result = __LINE__;
}
else
{
/* Codes_SRS_SASL_ANONYMOUS_01_012: [The bytes field of init_buffer shall be set to NULL.] */
init_bytes->bytes = NULL;
/* Codes_SRS_SASL_ANONYMOUS_01_006: [saslanonymous_get_init_bytes shall validate the concrete_sasl_mechanism argument and set the length of the init_bytes argument to be zero.] */
init_bytes->length = 0;
/* Codes_SRS_SASL_ANONYMOUS_01_011: [On success saslanonymous_get_init_bytes shall return zero.] */
result = 0;
}
return result;
}
const char* saslanonymous_get_mechanism_name(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism)
{
const char* result;
/* Codes_SRS_SASL_ANONYMOUS_01_009: [If the argument concrete_sasl_mechanism is NULL, saslanonymous_get_mechanism_name shall return NULL.] */
if (sasl_mechanism == NULL)
{
result = NULL;
}
else
{
/* Codes_SRS_SASL_ANONYMOUS_01_008: [saslanonymous_get_mechanism_name shall validate the argument concrete_sasl_mechanism and on success it shall return a pointer to the string “ANONYMOUS”.] */
result = "ANONYMOUS";
}
return result;
}
const SASL_MECHANISM_INTERFACE_DESCRIPTION* saslanonymous_get_interface(void)
{
return &saslanonymous_interface;
}

297
src/sasl_frame_codec.c Normal file
Просмотреть файл

@ -0,0 +1,297 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "sasl_frame_codec.h"
#include "frame_codec.h"
#include "amqpalloc.h"
#include "amqpvalue.h"
#include "amqp_definitions.h"
/* Requirements implemented by design or by other modules */
/* Codes_SRS_SASL_FRAME_CODEC_01_011: [A SASL frame has a type code of 0x01.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_016: [The maximum size of a SASL frame is defined by MIN-MAX-FRAME-SIZE.] */
#define MIX_MAX_FRAME_SIZE 512
typedef enum SASL_FRAME_DECODE_STATE_TAG
{
SASL_FRAME_DECODE_FRAME,
SASL_FRAME_DECODE_ERROR
} SASL_FRAME_DECODE_STATE;
typedef struct SASL_FRAME_CODEC_INSTANCE_TAG
{
FRAME_CODEC_HANDLE frame_codec;
/* decode */
ON_SASL_FRAME_RECEIVED on_sasl_frame_received;
ON_SASL_FRAME_CODEC_ERROR on_sasl_frame_codec_error;
void* callback_context;
AMQPVALUE_DECODER_HANDLE decoder;
SASL_FRAME_DECODE_STATE decode_state;
AMQP_VALUE decoded_sasl_frame_value;
} SASL_FRAME_CODEC_INSTANCE;
static void amqp_value_decoded(void* context, AMQP_VALUE decoded_value)
{
SASL_FRAME_CODEC_INSTANCE* sasl_frame_codec_instance = (SASL_FRAME_CODEC_INSTANCE*)context;
AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(decoded_value);
if (descriptor == NULL)
{
sasl_frame_codec_instance->decode_state = SASL_FRAME_DECODE_ERROR;
/* Codes_SRS_SASL_FRAME_CODEC_01_049: [If any error occurs while decoding a frame, the decoder shall call the on_sasl_frame_codec_error and pass to it the callback_context, both of those being the ones given to sasl_frame_codec_create.] */
sasl_frame_codec_instance->on_sasl_frame_codec_error(sasl_frame_codec_instance->callback_context);
}
else
{
/* Codes_SRS_SASL_FRAME_CODEC_01_009: [The frame body of a SASL frame MUST contain exactly one AMQP type, whose type encoding MUST have provides=“sasl-frame”.] */
if (!is_sasl_mechanisms_type_by_descriptor(descriptor) &&
!is_sasl_init_type_by_descriptor(descriptor) &&
!is_sasl_challenge_type_by_descriptor(descriptor) &&
!is_sasl_response_type_by_descriptor(descriptor) &&
!is_sasl_outcome_type_by_descriptor(descriptor))
{
sasl_frame_codec_instance->decode_state = SASL_FRAME_DECODE_ERROR;
/* Codes_SRS_SASL_FRAME_CODEC_01_049: [If any error occurs while decoding a frame, the decoder shall call the on_sasl_frame_codec_error and pass to it the callback_context, both of those being the ones given to sasl_frame_codec_create.] */
sasl_frame_codec_instance->on_sasl_frame_codec_error(sasl_frame_codec_instance->callback_context);
}
else
{
sasl_frame_codec_instance->decoded_sasl_frame_value = decoded_value;
}
}
}
static void frame_received(void* context, const unsigned char* type_specific, uint32_t type_specific_size, const unsigned char* frame_body, uint32_t frame_body_size)
{
SASL_FRAME_CODEC_INSTANCE* sasl_frame_codec_instance = (SASL_FRAME_CODEC_INSTANCE*)context;
/* Codes_SRS_SASL_FRAME_CODEC_01_006: [Bytes 6 and 7 of the header are ignored.] */
(void)type_specific;
/* Codes_SRS_SASL_FRAME_CODEC_01_007: [The extended header is ignored.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_008: [The maximum size of a SASL frame is defined by MIN-MAX-FRAME-SIZE.] */
if ((type_specific_size + frame_body_size + 6 > MIX_MAX_FRAME_SIZE) ||
/* Codes_SRS_SASL_FRAME_CODEC_01_010: [Receipt of an empty frame is an irrecoverable error.] */
(frame_body_size == 0))
{
/* error */
/* Codes_SRS_SASL_FRAME_CODEC_01_049: [If any error occurs while decoding a frame, the decoder shall call the on_sasl_frame_codec_error and pass to it the callback_context, both of those being the ones given to sasl_frame_codec_create.] */
sasl_frame_codec_instance->on_sasl_frame_codec_error(sasl_frame_codec_instance->callback_context);
}
else
{
switch (sasl_frame_codec_instance->decode_state)
{
default:
case SASL_FRAME_DECODE_ERROR:
/* error */
break;
case SASL_FRAME_DECODE_FRAME:
sasl_frame_codec_instance->decoded_sasl_frame_value = NULL;
/* Codes_SRS_SASL_FRAME_CODEC_01_039: [sasl_frame_codec shall decode the sasl-frame value as a described type.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_048: [Receipt of an empty frame is an irrecoverable error.] */
while ((frame_body_size > 0) &&
(sasl_frame_codec_instance->decoded_sasl_frame_value == NULL) &&
(sasl_frame_codec_instance->decode_state != SASL_FRAME_DECODE_ERROR))
{
/* Codes_SRS_SASL_FRAME_CODEC_01_040: [Decoding the sasl-frame type shall be done by feeding the bytes to the decoder create in sasl_frame_codec_create.] */
if (amqpvalue_decode_bytes(sasl_frame_codec_instance->decoder, frame_body, 1) != 0)
{
sasl_frame_codec_instance->decode_state = SASL_FRAME_DECODE_ERROR;
}
else
{
frame_body_size--;
frame_body++;
}
}
/* Codes_SRS_SASL_FRAME_CODEC_01_009: [The frame body of a SASL frame MUST contain exactly one AMQP type, whose type encoding MUST have provides=“sasl-frame”.] */
if (frame_body_size > 0)
{
sasl_frame_codec_instance->decode_state = SASL_FRAME_DECODE_ERROR;
/* Codes_SRS_SASL_FRAME_CODEC_01_049: [If any error occurs while decoding a frame, the decoder shall call the on_sasl_frame_codec_error and pass to it the callback_context, both of those being the ones given to sasl_frame_codec_create.] */
sasl_frame_codec_instance->on_sasl_frame_codec_error(sasl_frame_codec_instance->callback_context);
}
if (sasl_frame_codec_instance->decode_state == SASL_FRAME_DECODE_ERROR)
{
/* error */
}
else
{
/* Codes_SRS_SASL_FRAME_CODEC_01_041: [Once the sasl frame is decoded, the callback on_sasl_frame_received shall be called.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_042: [The decoded sasl-frame value and the context passed in sasl_frame_codec_create shall be passed to on_sasl_frame_received.] */
sasl_frame_codec_instance->on_sasl_frame_received(sasl_frame_codec_instance->callback_context, sasl_frame_codec_instance->decoded_sasl_frame_value);
}
break;
}
}
}
static int encode_bytes(void* context, const unsigned char* bytes, size_t length)
{
PAYLOAD* payload = (PAYLOAD*)context;
(void)memcpy((unsigned char*)payload->bytes + payload->length, bytes, length);
payload->length += length;
return 0;
}
SASL_FRAME_CODEC_HANDLE sasl_frame_codec_create(FRAME_CODEC_HANDLE frame_codec, ON_SASL_FRAME_RECEIVED on_sasl_frame_received, ON_SASL_FRAME_CODEC_ERROR on_sasl_frame_codec_error, void* callback_context)
{
SASL_FRAME_CODEC_INSTANCE* result;
/* Codes_SRS_SASL_FRAME_CODEC_01_019: [If any of the arguments frame_codec, on_sasl_frame_received or on_sasl_frame_codec_error is NULL, sasl_frame_codec_create shall return NULL.] */
if ((frame_codec == NULL) ||
(on_sasl_frame_received == NULL) ||
(on_sasl_frame_codec_error == NULL))
{
result = NULL;
}
else
{
/* Codes_SRS_SASL_FRAME_CODEC_01_018: [sasl_frame_codec_create shall create an instance of an sasl_frame_codec and return a non-NULL handle to it.] */
result = (SASL_FRAME_CODEC_INSTANCE*)amqpalloc_malloc(sizeof(SASL_FRAME_CODEC_INSTANCE));
if (result != NULL)
{
result->frame_codec = frame_codec;
result->on_sasl_frame_received = on_sasl_frame_received;
result->on_sasl_frame_codec_error = on_sasl_frame_codec_error;
result->callback_context = callback_context;
result->decode_state = SASL_FRAME_DECODE_FRAME;
/* Codes_SRS_SASL_FRAME_CODEC_01_022: [sasl_frame_codec_create shall create a decoder to be used for decoding SASL values.] */
result->decoder = amqpvalue_decoder_create(amqp_value_decoded, result);
if (result->decoder == NULL)
{
/* Codes_SRS_SASL_FRAME_CODEC_01_023: [If creating the decoder fails, sasl_frame_codec_create shall fail and return NULL.] */
amqpalloc_free(result);
result = NULL;
}
else
{
/* Codes_SRS_SASL_FRAME_CODEC_01_020: [sasl_frame_codec_create shall subscribe for SASL frames with the given frame_codec.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_001: [A SASL frame has a type code of 0x01.] */
if (frame_codec_subscribe(frame_codec, FRAME_TYPE_SASL, frame_received, result) != 0)
{
/* Codes_SRS_SASL_FRAME_CODEC_01_021: [If subscribing for SASL frames fails, sasl_frame_codec_create shall fail and return NULL.] */
amqpvalue_decoder_destroy(result->decoder);
amqpalloc_free(result);
result = NULL;
}
}
}
}
return result;
}
void sasl_frame_codec_destroy(SASL_FRAME_CODEC_HANDLE sasl_frame_codec)
{
/* Codes_SRS_SASL_FRAME_CODEC_01_026: [If sasl_frame_codec is NULL, sasl_frame_codec_destroy shall do nothing.] */
if (sasl_frame_codec != NULL)
{
/* Codes_SRS_SASL_FRAME_CODEC_01_025: [sasl_frame_codec_destroy shall free all resources associated with the sasl_frame_codec instance.] */
SASL_FRAME_CODEC_INSTANCE* sasl_frame_codec_instance = (SASL_FRAME_CODEC_INSTANCE*)sasl_frame_codec;
/* Codes_SRS_SASL_FRAME_CODEC_01_027: [sasl_frame_codec_destroy shall unsubscribe from receiving SASL frames from the frame_codec that was passed to sasl_frame_codec_create.] */
(void)frame_codec_unsubscribe(sasl_frame_codec_instance->frame_codec, FRAME_TYPE_SASL);
/* Codes_SRS_SASL_FRAME_CODEC_01_028: [The decoder created in sasl_frame_codec_create shall be destroyed by sasl_frame_codec_destroy.] */
amqpvalue_decoder_destroy(sasl_frame_codec_instance->decoder);
amqpalloc_free(sasl_frame_codec_instance);
}
}
/* Codes_SRS_SASL_FRAME_CODEC_01_029: [sasl_frame_codec_encode_frame shall encode the frame header and sasl_frame_value AMQP value in a SASL frame and on success it shall return 0.] */
int sasl_frame_codec_encode_frame(SASL_FRAME_CODEC_HANDLE sasl_frame_codec, const AMQP_VALUE sasl_frame_value, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context)
{
int result;
SASL_FRAME_CODEC_INSTANCE* sasl_frame_codec_instance = (SASL_FRAME_CODEC_INSTANCE*)sasl_frame_codec;
/* Codes_SRS_SASL_FRAME_CODEC_01_030: [If sasl_frame_codec or sasl_frame_value is NULL, sasl_frame_codec_encode_frame shall fail and return a non-zero value.] */
if ((sasl_frame_codec == NULL) ||
(sasl_frame_value == NULL))
{
/* Codes_SRS_SASL_FRAME_CODEC_01_034: [If any error occurs during encoding, sasl_frame_codec_encode_frame shall fail and return a non-zero value.] */
result = __LINE__;
}
else
{
AMQP_VALUE descriptor;
uint64_t sasl_frame_descriptor_ulong;
size_t encoded_size;
if (((descriptor = amqpvalue_get_inplace_descriptor(sasl_frame_value)) == NULL) ||
(amqpvalue_get_ulong(descriptor, &sasl_frame_descriptor_ulong) != 0) ||
/* Codes_SRS_SASL_FRAME_CODEC_01_047: [The frame body of a SASL frame MUST contain exactly one AMQP type, whose type encoding MUST have provides=“sasl-frame”.] */
(sasl_frame_descriptor_ulong < SASL_MECHANISMS) ||
(sasl_frame_descriptor_ulong > SASL_OUTCOME))
{
/* Codes_SRS_SASL_FRAME_CODEC_01_034: [If any error occurs during encoding, sasl_frame_codec_encode_frame shall fail and return a non-zero value.] */
result = __LINE__;
}
/* Codes_SRS_SASL_FRAME_CODEC_01_032: [The payload frame size shall be computed based on the encoded size of the sasl_frame_value and its fields.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_033: [The encoded size of the sasl_frame_value and its fields shall be obtained by calling amqpvalue_get_encoded_size.] */
else if ((amqpvalue_get_encoded_size(sasl_frame_value, &encoded_size) != 0) ||
/* Codes_SRS_SASL_FRAME_CODEC_01_016: [The maximum size of a SASL frame is defined by MIN-MAX-FRAME-SIZE.] */
(encoded_size > MIX_MAX_FRAME_SIZE - 8))
{
/* Codes_SRS_SASL_FRAME_CODEC_01_034: [If any error occurs during encoding, sasl_frame_codec_encode_frame shall fail and return a non-zero value.] */
result = __LINE__;
}
else
{
unsigned char* sasl_frame_bytes = (unsigned char*)amqpalloc_malloc(encoded_size);
if (sasl_frame_bytes == NULL)
{
result = __LINE__;
}
else
{
PAYLOAD payload = { sasl_frame_bytes, 0 };
if (amqpvalue_encode(sasl_frame_value, encode_bytes, &payload) != 0)
{
result = __LINE__;
}
else
{
/* Codes_SRS_SASL_FRAME_CODEC_01_031: [sasl_frame_codec_encode_frame shall encode the frame header and its contents by using frame_codec_encode_frame.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_012: [Bytes 6 and 7 of the header are ignored.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_013: [Implementations SHOULD set these to 0x00.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_014: [The extended header is ignored.] */
/* Codes_SRS_SASL_FRAME_CODEC_01_015: [Implementations SHOULD therefore set DOFF to 0x02.] */
if (frame_codec_encode_frame(sasl_frame_codec_instance->frame_codec, FRAME_TYPE_SASL, &payload, 1, NULL, 0, on_bytes_encoded, callback_context) != 0)
{
/* Codes_SRS_SASL_FRAME_CODEC_01_034: [If any error occurs during encoding, sasl_frame_codec_encode_frame shall fail and return a non-zero value.] */
result = __LINE__;
}
else
{
result = 0;
}
}
amqpalloc_free(sasl_frame_bytes);
}
}
}
return result;
}

122
src/sasl_mechanism.c Normal file
Просмотреть файл

@ -0,0 +1,122 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include "sasl_mechanism.h"
#include "amqpalloc.h"
typedef struct SASL_MECHANISM_INSTANCE_TAG
{
const SASL_MECHANISM_INTERFACE_DESCRIPTION* sasl_mechanism_interface_description;
CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism_handle;
} SASL_MECHANISM_INSTANCE;
SASL_MECHANISM_HANDLE saslmechanism_create(const SASL_MECHANISM_INTERFACE_DESCRIPTION* sasl_mechanism_interface_description, void* sasl_mechanism_create_parameters)
{
SASL_MECHANISM_INSTANCE* sasl_mechanism_instance;
/* Codes_SRS_SASL_MECHANISM_01_004: [If the argument sasl_mechanism_interface_description is NULL, saslmechanism_create shall return NULL.] */
if ((sasl_mechanism_interface_description == NULL) ||
/* Codes_SRS_SASL_MECHANISM_01_005: [If any sasl_mechanism_interface_description member is NULL, sasl_mechanism_create shall fail and return NULL.] */
(sasl_mechanism_interface_description->concrete_sasl_mechanism_create == NULL) ||
(sasl_mechanism_interface_description->concrete_sasl_mechanism_destroy == NULL) ||
(sasl_mechanism_interface_description->concrete_sasl_mechanism_get_init_bytes == NULL) ||
(sasl_mechanism_interface_description->concrete_sasl_mechanism_get_mechanism_name == NULL))
{
sasl_mechanism_instance = NULL;
}
else
{
sasl_mechanism_instance = (SASL_MECHANISM_INSTANCE*)amqpalloc_malloc(sizeof(SASL_MECHANISM_INSTANCE));
if (sasl_mechanism_instance != NULL)
{
sasl_mechanism_instance->sasl_mechanism_interface_description = sasl_mechanism_interface_description;
/* Codes_SRS_SASL_MECHANISM_01_002: [In order to instantiate the concrete SASL mechanism implementation the function concrete_sasl_mechanism_create from the sasl_mechanism_interface_description shall be called, passing the sasl_mechanism_create_parameters to it.] */
sasl_mechanism_instance->concrete_sasl_mechanism_handle = sasl_mechanism_instance->sasl_mechanism_interface_description->concrete_sasl_mechanism_create((void*)sasl_mechanism_create_parameters);
if (sasl_mechanism_instance->concrete_sasl_mechanism_handle == NULL)
{
/* Codes_SRS_SASL_MECHANISM_01_003: [If the underlying concrete_sasl_mechanism_create call fails, saslmechanism_create shall return NULL.] */
amqpalloc_free(sasl_mechanism_instance);
sasl_mechanism_instance = NULL;
}
}
}
/* Codes_SRS_SASL_MECHANISM_01_001: [saslmechanism_create shall return on success a non-NULL handle to a new SASL mechanism interface.] */
return (SASL_MECHANISM_HANDLE)sasl_mechanism_instance;
}
void saslmechanism_destroy(SASL_MECHANISM_HANDLE sasl_mechanism)
{
if (sasl_mechanism != NULL)
{
SASL_MECHANISM_INSTANCE* sasl_mechanism_instance = (SASL_MECHANISM_INSTANCE*)sasl_mechanism;
/* Codes_SRS_SASL_MECHANISM_01_008: [saslmechanism_destroy shall also call the concrete_sasl_mechanism_destroy function that is member of the sasl_mechanism_interface_description argument passed to saslmechanism_create, while passing as argument to concrete_sasl_mechanism_destroy the result of the underlying concrete SASL mechanism handle.] */
sasl_mechanism_instance->sasl_mechanism_interface_description->concrete_sasl_mechanism_destroy(sasl_mechanism_instance->concrete_sasl_mechanism_handle);
/* Codes_SRS_SASL_MECHANISM_01_007: [saslmechanism_destroy shall free all resources associated with the SASL mechanism handle.] */
amqpalloc_free(sasl_mechanism_instance);
}
}
int saslmechanism_get_init_bytes(SASL_MECHANISM_HANDLE sasl_mechanism, SASL_MECHANISM_BYTES* init_bytes)
{
int result;
/* Codes_SRS_SASL_MECHANISM_01_012: [If the argument sasl_mechanism is NULL, saslmechanism_get_init_bytes shall fail and return a non-zero value.] */
if (sasl_mechanism == NULL)
{
result = __LINE__;
}
else
{
SASL_MECHANISM_INSTANCE* sasl_mechanism_instance = (SASL_MECHANISM_INSTANCE*)sasl_mechanism;
/* Codes_SRS_SASL_MECHANISM_01_010: [saslmechanism_get_init_bytes shall call the specific concrete_sasl_mechanism_get_init_bytes function specified in saslmechanism_create, passing the init_bytes argument to it.] */
if (sasl_mechanism_instance->sasl_mechanism_interface_description->concrete_sasl_mechanism_get_init_bytes(sasl_mechanism_instance->concrete_sasl_mechanism_handle, init_bytes) != 0)
{
/* Codes_SRS_SASL_MECHANISM_01_013: [If the underlying concrete_sasl_mechanism_get_init_bytes fails, saslmechanism_get_init_bytes shall fail and return a non-zero value.] */
result = __LINE__;
}
else
{
/* Codes_SRS_SASL_MECHANISM_01_011: [On success, saslmechanism_get_init_bytes shall return 0.] */
result = 0;
}
}
return result;
}
const char* saslmechanism_get_mechanism_name(SASL_MECHANISM_HANDLE sasl_mechanism)
{
const char* result;
/* Codes_SRS_SASL_MECHANISM_01_016: [If the argument sasl_mechanism is NULL, saslmechanism_get_mechanism_name shall fail and return a non-zero value.] */
if (sasl_mechanism == NULL)
{
result = NULL;
}
else
{
SASL_MECHANISM_INSTANCE* sasl_mechanism_instance = (SASL_MECHANISM_INSTANCE*)sasl_mechanism;
/* Codes_SRS_SASL_MECHANISM_01_014: [saslmechanism_get_mechanism_name shall call the specific concrete_sasl_mechanism_get_mechanism_name function specified in saslmechanism_create.] */
/* Codes_SRS_SASL_MECHANISM_01_015: [On success, saslmechanism_get_mechanism_name shall return a pointer to a string with the mechanism name.] */
/* Codes_SRS_SASL_MECHANISM_01_017: [If the underlying concrete_sasl_mechanism_get_mechanism_name fails, saslmechanism_get_mechanism_name shall return NULL.] */
result = sasl_mechanism_instance->sasl_mechanism_interface_description->concrete_sasl_mechanism_get_mechanism_name(sasl_mechanism_instance->concrete_sasl_mechanism_handle);
}
return result;
}
int saslmechanism_challenge(SASL_MECHANISM_HANDLE sasl_mechanism, const SASL_MECHANISM_BYTES* challenge_bytes, SASL_MECHANISM_BYTES* response_bytes)
{
return 0;
}

76
src/sasl_mssbcbs.c Normal file
Просмотреть файл

@ -0,0 +1,76 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <string.h>
#include "sasl_mssbcbs.h"
#include "amqpalloc.h"
typedef struct SASL_MSSBCBS_INSTANCE_TAG
{
unsigned char dummy : 1;
} SASL_MSSBCBS_INSTANCE;
static const SASL_MECHANISM_INTERFACE_DESCRIPTION saslmssbcbs_interface =
{
saslmssbcbs_create,
saslmssbcbs_destroy,
saslmssbcbs_get_init_bytes,
saslmssbcbs_get_mechanism_name
};
CONCRETE_SASL_MECHANISM_HANDLE saslmssbcbs_create(void* config)
{
return amqpalloc_malloc(sizeof(SASL_MSSBCBS_INSTANCE));
}
void saslmssbcbs_destroy(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle)
{
if (sasl_mechanism_concrete_handle != NULL)
{
amqpalloc_free(sasl_mechanism_concrete_handle);
}
}
int saslmssbcbs_get_init_bytes(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle, SASL_MECHANISM_BYTES* init_bytes)
{
int result;
if (sasl_mechanism_concrete_handle == NULL)
{
result = __LINE__;
}
else
{
init_bytes->bytes = NULL;
init_bytes->length = 0;
result = 0;
}
return result;
}
const char* saslmssbcbs_get_mechanism_name(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism)
{
const char* result;
if (sasl_mechanism == NULL)
{
result = NULL;
}
else
{
result = "MSSBCBS";
}
return result;
}
const SASL_MECHANISM_INTERFACE_DESCRIPTION* saslmssbcbs_get_interface(void)
{
return &saslmssbcbs_interface;
}

109
src/sasl_plain.c Normal file
Просмотреть файл

@ -0,0 +1,109 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <string.h>
#include "sasl_plain.h"
#include "amqpalloc.h"
typedef struct SASL_PLAIN_INSTANCE_TAG
{
unsigned char* init_bytes;
size_t init_bytes_length;
} SASL_PLAIN_INSTANCE;
static const SASL_MECHANISM_INTERFACE_DESCRIPTION saslplain_interface =
{
saslplain_create,
saslplain_destroy,
saslplain_get_init_bytes,
saslplain_get_mechanism_name
};
CONCRETE_SASL_MECHANISM_HANDLE saslplain_create(void* config)
{
SASL_PLAIN_INSTANCE* result = amqpalloc_malloc(sizeof(SASL_PLAIN_INSTANCE));
if (result != NULL)
{
SASL_PLAIN_CONFIG* sasl_plain_config = (SASL_PLAIN_CONFIG*)config;
size_t authcid_length = strlen(sasl_plain_config->authcid);
size_t passwd_length = strlen(sasl_plain_config->passwd);
/* Ignore UTF8 for now */
result->init_bytes = (unsigned char*)amqpalloc_malloc(authcid_length + passwd_length + 2);
if (result->init_bytes == NULL)
{
amqpalloc_free(result);
result = NULL;
}
else
{
result->init_bytes[0] = 0;
(void)memcpy(result->init_bytes + 1, sasl_plain_config->authcid, authcid_length);
result->init_bytes[authcid_length + 1] = 0;
(void)memcpy(result->init_bytes + authcid_length + 2, sasl_plain_config->passwd, passwd_length);
result->init_bytes_length = authcid_length + passwd_length + 2;
}
}
return result;
}
void saslplain_destroy(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle)
{
if (sasl_mechanism_concrete_handle != NULL)
{
SASL_PLAIN_INSTANCE* sasl_plain_instance = (SASL_PLAIN_INSTANCE*)sasl_mechanism_concrete_handle;
if (sasl_plain_instance->init_bytes != NULL)
{
amqpalloc_free(sasl_plain_instance->init_bytes);
}
amqpalloc_free(sasl_plain_instance);
}
}
int saslplain_get_init_bytes(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle, SASL_MECHANISM_BYTES* init_bytes)
{
int result;
if (sasl_mechanism_concrete_handle == NULL)
{
result = __LINE__;
}
else
{
SASL_PLAIN_INSTANCE* sasl_plain_instance = (SASL_PLAIN_INSTANCE*)sasl_mechanism_concrete_handle;
init_bytes->bytes = sasl_plain_instance->init_bytes;
init_bytes->length = sasl_plain_instance->init_bytes_length;
result = 0;
}
return result;
}
const char* saslplain_get_mechanism_name(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism)
{
const char* result;
if (sasl_mechanism == NULL)
{
result = NULL;
}
else
{
result = "PLAIN";
}
return result;
}
const SASL_MECHANISM_INTERFACE_DESCRIPTION* saslplain_get_interface(void)
{
return &saslplain_interface;
}

1007
src/saslclientio.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

1543
src/session.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

164
src/socket_listener_win32.c Normal file
Просмотреть файл

@ -0,0 +1,164 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include "socket_listener.h"
#include "amqpalloc.h"
#include "winsock2.h"
#include "ws2tcpip.h"
#include "windows.h"
#include "socketio.h"
typedef struct SOCKET_LISTENER_INSTANCE_TAG
{
int port;
SOCKET socket;
ON_SOCKET_ACCEPTED on_socket_accepted;
void* callback_context;
} SOCKET_LISTENER_INSTANCE;
SOCKET_LISTENER_HANDLE socketlistener_create(int port)
{
SOCKET_LISTENER_INSTANCE* result = (SOCKET_LISTENER_INSTANCE*)amqpalloc_malloc(sizeof(SOCKET_LISTENER_INSTANCE));
if (result != NULL)
{
result->port = port;
result->on_socket_accepted = NULL;
result->callback_context = NULL;
}
return (SOCKET_LISTENER_HANDLE)result;
}
void socketlistener_destroy(SOCKET_LISTENER_HANDLE socket_listener)
{
if (socket_listener != NULL)
{
socketlistener_stop(socket_listener);
amqpalloc_free(socket_listener);
}
}
int socketlistener_start(SOCKET_LISTENER_HANDLE socket_listener, ON_SOCKET_ACCEPTED on_socket_accepted, void* callback_context)
{
int result;
if (socket_listener == NULL)
{
result = __LINE__;
}
else
{
SOCKET_LISTENER_INSTANCE* socket_listener_instance = (SOCKET_LISTENER_INSTANCE*)socket_listener;
socket_listener_instance->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socket_listener_instance->socket == INVALID_SOCKET)
{
result = __LINE__;
}
else
{
socket_listener_instance->on_socket_accepted = on_socket_accepted;
socket_listener_instance->callback_context = callback_context;
ADDRINFO* addrInfo = NULL;
char portString[16];
ADDRINFO addrHint = { 0 };
addrHint.ai_family = AF_INET;
addrHint.ai_socktype = SOCK_STREAM;
addrHint.ai_protocol = 0;
sprintf(portString, "%u", socket_listener_instance->port);
if (getaddrinfo(NULL, portString, &addrHint, &addrInfo) != 0)
{
(void)closesocket(socket_listener_instance->socket);
socket_listener_instance->socket = INVALID_SOCKET;
result = __LINE__;
}
else
{
u_long iMode = 1;
if (bind(socket_listener_instance->socket, addrInfo->ai_addr, addrInfo->ai_addrlen) == SOCKET_ERROR)
{
(void)closesocket(socket_listener_instance->socket);
socket_listener_instance->socket = INVALID_SOCKET;
result = __LINE__;
}
else if (ioctlsocket(socket_listener_instance->socket, FIONBIO, &iMode) != 0)
{
(void)closesocket(socket_listener_instance->socket);
socket_listener_instance->socket = INVALID_SOCKET;
result = __LINE__;
}
else
{
if (listen(socket_listener_instance->socket, SOMAXCONN) == SOCKET_ERROR)
{
(void)closesocket(socket_listener_instance->socket);
socket_listener_instance->socket = INVALID_SOCKET;
result = __LINE__;
}
else
{
result = 0;
}
}
}
}
}
return result;
}
int socketlistener_stop(SOCKET_LISTENER_HANDLE socket_listener)
{
int result;
if (socket_listener == NULL)
{
result = __LINE__;
}
else
{
SOCKET_LISTENER_INSTANCE* socket_listener_instance = (SOCKET_LISTENER_INSTANCE*)socket_listener;
socket_listener_instance->on_socket_accepted = NULL;
socket_listener_instance->callback_context = NULL;
(void)closesocket(socket_listener_instance->socket);
socket_listener_instance->socket = INVALID_SOCKET;
result = 0;
}
return result;
}
void socketlistener_dowork(SOCKET_LISTENER_HANDLE socket_listener)
{
if (socket_listener != NULL)
{
SOCKET_LISTENER_INSTANCE* socket_listener_instance = (SOCKET_LISTENER_INSTANCE*)socket_listener;
SOCKET accepted_socket = accept(socket_listener_instance->socket, NULL, NULL);
if (accepted_socket != INVALID_SOCKET)
{
if (socket_listener_instance->on_socket_accepted != NULL)
{
SOCKETIO_CONFIG socketio_config = { NULL, socket_listener_instance->port, &accepted_socket };
XIO_HANDLE io = xio_create(socketio_get_interface_description(), &socketio_config, NULL);
if (io == NULL)
{
(void)closesocket(accepted_socket);
}
else
{
socket_listener_instance->on_socket_accepted(socket_listener_instance->callback_context, io);
}
}
else
{
(void)closesocket(accepted_socket);
}
}
}
}

529
src/wsio.c Normal file
Просмотреть файл

@ -0,0 +1,529 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <stddef.h>
#include <stdio.h>
#include "wsio.h"
#include "amqpalloc.h"
#include "logger.h"
#include "list.h"
#include "libwebsockets.h"
typedef struct PENDING_SOCKET_IO_TAG
{
unsigned char* bytes;
size_t size;
ON_SEND_COMPLETE on_send_complete;
void* callback_context;
LIST_HANDLE pending_io_list;
} PENDING_SOCKET_IO;
typedef struct WSIO_INSTANCE_TAG
{
ON_BYTES_RECEIVED on_bytes_received;
ON_IO_STATE_CHANGED on_io_state_changed;
LOGGER_LOG logger_log;
void* callback_context;
IO_STATE io_state;
LIST_HANDLE pending_io_list;
struct libwebsocket_context* ws_context;
struct libwebsocket* wsi;
int port;
char* host;
char* relative_path;
char* trusted_ca;
struct libwebsocket_protocols* protocols;
bool use_ssl;
} WSIO_INSTANCE;
static int add_pending_io(WSIO_INSTANCE* ws_io_instance, const unsigned char* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
{
int result;
PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)amqpalloc_malloc(sizeof(PENDING_SOCKET_IO));
if (pending_socket_io == NULL)
{
result = __LINE__;
}
else
{
pending_socket_io->bytes = (unsigned char*)amqpalloc_malloc(size);
if (pending_socket_io->bytes == NULL)
{
amqpalloc_free(pending_socket_io);
result = __LINE__;
}
else
{
pending_socket_io->size = size;
pending_socket_io->on_send_complete = on_send_complete;
pending_socket_io->callback_context = callback_context;
pending_socket_io->pending_io_list = ws_io_instance->pending_io_list;
(void)memcpy(pending_socket_io->bytes, buffer, size);
if (list_add(ws_io_instance->pending_io_list, pending_socket_io) == NULL)
{
amqpalloc_free(pending_socket_io->bytes);
amqpalloc_free(pending_socket_io);
result = __LINE__;
}
else
{
result = 0;
}
}
}
return result;
}
static const IO_INTERFACE_DESCRIPTION ws_io_interface_description =
{
wsio_create,
wsio_destroy,
wsio_open,
wsio_close,
wsio_send,
wsio_dowork
};
static void set_io_state(WSIO_INSTANCE* wsio_instance, IO_STATE io_state)
{
IO_STATE previous_state = wsio_instance->io_state;
wsio_instance->io_state = io_state;
if (wsio_instance->on_io_state_changed != NULL)
{
wsio_instance->on_io_state_changed(wsio_instance->callback_context, io_state, previous_state);
}
}
static int ws_sb_cbs_callback(struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len)
{
WSIO_INSTANCE* wsio_instance = libwebsocket_context_user(this);
switch (reason)
{
case LWS_CALLBACK_CLIENT_ESTABLISHED:
set_io_state(wsio_instance, IO_STATE_OPEN);
break;
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
set_io_state(wsio_instance, IO_STATE_ERROR);
break;
case LWS_CALLBACK_CLOSED:
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
{
WSIO_INSTANCE* wsio_instance = libwebsocket_context_user(this);
LIST_ITEM_HANDLE first_pending_io = list_get_head_item(wsio_instance->pending_io_list);
if (first_pending_io != NULL)
{
PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)list_item_get_value(first_pending_io);
if (pending_socket_io == NULL)
{
set_io_state(wsio_instance, IO_STATE_ERROR);
}
else
{
unsigned char* ws_buffer = (unsigned char*)amqpalloc_malloc(LWS_SEND_BUFFER_PRE_PADDING + pending_socket_io->size + LWS_SEND_BUFFER_POST_PADDING);
if (ws_buffer == NULL)
{
set_io_state(wsio_instance, IO_STATE_ERROR);
}
else
{
(void)memcpy(ws_buffer + LWS_SEND_BUFFER_PRE_PADDING, pending_socket_io->bytes, pending_socket_io->size);
int n = libwebsocket_write(wsio_instance->wsi, &ws_buffer[LWS_SEND_BUFFER_PRE_PADDING], pending_socket_io->size, LWS_WRITE_BINARY);
if (n < 0)
{
/* error */
set_io_state(wsio_instance, IO_STATE_ERROR);
pending_socket_io->on_send_complete(pending_socket_io->callback_context, IO_SEND_ERROR);
}
else
{
if ((size_t)n < pending_socket_io->size)
{
/* make pending */
(void)memmove(pending_socket_io->bytes, pending_socket_io->bytes + n, (pending_socket_io->size - (size_t)n));
}
else
{
if (pending_socket_io->on_send_complete != NULL)
{
pending_socket_io->on_send_complete(pending_socket_io->callback_context, IO_SEND_OK);
}
amqpalloc_free(pending_socket_io->bytes);
amqpalloc_free(pending_socket_io);
if (list_remove(wsio_instance->pending_io_list, first_pending_io) != 0)
{
set_io_state(wsio_instance, IO_STATE_ERROR);
}
}
}
if (list_get_head_item(wsio_instance->pending_io_list) != NULL)
{
(void)libwebsocket_callback_on_writable(this, wsi);
}
amqpalloc_free(ws_buffer);
}
}
}
break;
}
case LWS_CALLBACK_CLIENT_RECEIVE:
{
WSIO_INSTANCE* wsio_instance = libwebsocket_context_user(this);
wsio_instance->on_bytes_received(wsio_instance->callback_context, in, len);
break;
}
case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
break;
case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
{
X509_STORE* cert_store = SSL_CTX_get_cert_store(user);
BIO* cert_memory_bio;
X509* certificate;
cert_memory_bio = BIO_new(BIO_s_mem());
if (cert_memory_bio == NULL)
{
/* error */
}
else
{
if (BIO_puts(cert_memory_bio, wsio_instance->trusted_ca) < (int)strlen(wsio_instance->trusted_ca))
{
/* error */
}
else
{
do
{
certificate = PEM_read_bio_X509(cert_memory_bio, NULL, 0, NULL);
if (certificate != NULL)
{
if (!X509_STORE_add_cert(cert_store, certificate))
{
break;
}
}
} while (certificate != NULL);
if (certificate != NULL)
{
/* error */
}
}
BIO_free(cert_memory_bio);
}
break;
}
default:
break;
}
return 0;
}
CONCRETE_IO_HANDLE wsio_create(void* io_create_parameters, LOGGER_LOG logger_log)
{
WSIO_CONFIG* ws_io_config = io_create_parameters;
WSIO_INSTANCE* result;
if ((ws_io_config == NULL) ||
(ws_io_config->host == NULL) ||
(ws_io_config->protocol_name == NULL) ||
(ws_io_config->relative_path == NULL))
{
result = NULL;
}
else
{
result = amqpalloc_malloc(sizeof(WSIO_INSTANCE));
if (result != NULL)
{
result->on_bytes_received = NULL;
result->on_io_state_changed = NULL;
result->logger_log = logger_log;
result->callback_context = NULL;
result->wsi = NULL;
result->ws_context = NULL;
result->pending_io_list = list_create();
if (result->pending_io_list == NULL)
{
amqpalloc_free(result);
result = NULL;
}
else
{
result->host = (char*)amqpalloc_malloc(strlen(ws_io_config->host) + 1);
if (result->host == NULL)
{
list_destroy(result->pending_io_list);
amqpalloc_free(result);
result = NULL;
}
else
{
result->relative_path = (char*)amqpalloc_malloc(strlen(ws_io_config->relative_path) + 1);
if (result->relative_path == NULL)
{
amqpalloc_free(result->host);
list_destroy(result->pending_io_list);
amqpalloc_free(result);
result = NULL;
}
else
{
result->protocols = (struct libwebsocket_protocols*)amqpalloc_malloc(sizeof(struct libwebsocket_protocols) * 2);
if (result->protocols == NULL)
{
amqpalloc_free(result->relative_path);
amqpalloc_free(result->host);
list_destroy(result->pending_io_list);
amqpalloc_free(result);
result = NULL;
}
else
{
result->trusted_ca = NULL;
result->protocols[0].callback = ws_sb_cbs_callback;
result->protocols[0].id = 0;
result->protocols[0].name = ws_io_config->protocol_name;
result->protocols[0].owning_server = NULL;
result->protocols[0].per_session_data_size = 0;
result->protocols[0].protocol_index = 0;
result->protocols[0].rx_buffer_size = 1;
result->protocols[0].user = NULL;
result->protocols[1].callback = NULL;
result->protocols[1].id = 0;
result->protocols[1].name = NULL;
result->protocols[1].owning_server = NULL;
result->protocols[1].per_session_data_size = 0;
result->protocols[1].protocol_index = 0;
result->protocols[1].rx_buffer_size = 0;
result->protocols[1].user = NULL;
(void)strcpy(result->host, ws_io_config->host);
(void)strcpy(result->relative_path, ws_io_config->relative_path);
result->port = ws_io_config->port;
result->use_ssl = ws_io_config->use_ssl;
set_io_state(result, IO_STATE_NOT_OPEN);
if (ws_io_config->trusted_ca != NULL)
{
result->trusted_ca = (char*)amqpalloc_malloc(strlen(ws_io_config->trusted_ca) + 1);
if (result->trusted_ca == NULL)
{
amqpalloc_free(result->protocols);
amqpalloc_free(result->relative_path);
amqpalloc_free(result->host);
list_destroy(result->pending_io_list);
amqpalloc_free(result);
result = NULL;
}
else
{
(void)strcpy(result->trusted_ca, ws_io_config->trusted_ca);
}
}
}
}
}
}
}
}
return result;
}
void wsio_destroy(CONCRETE_IO_HANDLE ws_io)
{
if (ws_io != NULL)
{
WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
/* clear all pending IOs */
LIST_ITEM_HANDLE first_pending_io;
while ((first_pending_io = list_get_head_item(wsio_instance->pending_io_list)) != NULL)
{
PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)list_item_get_value(first_pending_io);
if (pending_socket_io != NULL)
{
amqpalloc_free(pending_socket_io->bytes);
amqpalloc_free(pending_socket_io);
}
list_remove(wsio_instance->pending_io_list, first_pending_io);
}
amqpalloc_free(wsio_instance->protocols);
amqpalloc_free(wsio_instance->host);
amqpalloc_free(wsio_instance->relative_path);
amqpalloc_free(wsio_instance->trusted_ca);
list_destroy(wsio_instance->pending_io_list);
amqpalloc_free(ws_io);
}
}
int wsio_open(CONCRETE_IO_HANDLE ws_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context)
{
int result = 0;
if (ws_io == NULL)
{
result = __LINE__;
}
else
{
WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
wsio_instance->on_bytes_received = on_bytes_received;
wsio_instance->on_io_state_changed = on_io_state_changed;
wsio_instance->callback_context = callback_context;
int ietf_version = -1; /* latest */
struct lws_context_creation_info info;
memset(&info, 0, sizeof info);
info.port = CONTEXT_PORT_NO_LISTEN;
info.protocols = wsio_instance->protocols;
info.extensions = libwebsocket_get_internal_extensions();
info.gid = -1;
info.uid = -1;
info.user = wsio_instance;
wsio_instance->ws_context = libwebsocket_create_context(&info);
if (wsio_instance->ws_context == NULL)
{
printf("Creating libwebsocket context failed\n");
result = __LINE__;
}
else
{
wsio_instance->wsi = libwebsocket_client_connect(wsio_instance->ws_context, wsio_instance->host, wsio_instance->port, wsio_instance->use_ssl, wsio_instance->relative_path, wsio_instance->host, wsio_instance->host, wsio_instance->protocols[0].name, ietf_version);
if (wsio_instance->wsi == NULL)
{
result = __LINE__;
}
else
{
set_io_state(wsio_instance, IO_STATE_OPENING);
result = 0;
}
}
}
return result;
}
int wsio_close(CONCRETE_IO_HANDLE ws_io)
{
int result = 0;
if (ws_io == NULL)
{
result = __LINE__;
}
else
{
WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
if (wsio_instance->io_state != IO_STATE_NOT_OPEN)
{
libwebsocket_context_destroy(wsio_instance->ws_context);
set_io_state(wsio_instance, IO_STATE_NOT_OPEN);
}
result = 0;
}
return result;
}
int wsio_send(CONCRETE_IO_HANDLE ws_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
{
int result;
if ((ws_io == NULL) ||
(buffer == NULL) ||
(size == 0))
{
/* Invalid arguments */
result = __LINE__;
}
else
{
WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
if (wsio_instance->io_state != IO_STATE_OPEN)
{
result = __LINE__;
}
else
{
if (wsio_instance->logger_log != NULL)
{
size_t i;
for (i = 0; i < size; i++)
{
LOG(wsio_instance->logger_log, 0, " %02x", ((const unsigned char*)buffer)[i]);
}
}
if (add_pending_io(wsio_instance, buffer, size, on_send_complete, callback_context) != 0)
{
result = __LINE__;
}
else
{
(void)libwebsocket_callback_on_writable(wsio_instance->ws_context, wsio_instance->wsi);
result = 0;
}
}
}
return result;
}
void wsio_dowork(CONCRETE_IO_HANDLE ws_io)
{
if (ws_io != NULL)
{
WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
if ((wsio_instance->io_state == IO_STATE_OPEN) ||
(wsio_instance->io_state == IO_STATE_OPENING))
{
(void)libwebsocket_service(wsio_instance->ws_context, 0);
}
}
}
const IO_INTERFACE_DESCRIPTION* wsio_get_interface_description(void)
{
return &ws_io_interface_description;
}

14
tests/CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,14 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
add_subdirectory(amqp_frame_codec_unittests)
add_subdirectory(amqpvalue_limits_unittests)
add_subdirectory(amqpvalue_unittests)
add_subdirectory(connection_unittests)
add_subdirectory(frame_codec_unittests)
add_subdirectory(message_unittests)
add_subdirectory(sasl_anonymous_unittests)
add_subdirectory(sasl_frame_codec_unittests)
add_subdirectory(sasl_mechanism_unittests)
add_subdirectory(session_unittests)
add_subdirectory(saslclientio_unittests)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,19 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
cmake_minimum_required(VERSION 3.0)
compileAsC99()
set(theseTestsName amqp_frame_codec_unittests)
set(${theseTestsName}_cpp_files
${theseTestsName}.cpp
)
set(${theseTestsName}_c_files
../../src/amqp_frame_codec.c
)
set(${theseTestsName}_h_files
)
build_test_artifacts(${theseTestsName} ON)

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше