├── .gitignore ├── LICENSE.md ├── .travis.yml ├── Dockerfile ├── SConstruct ├── src ├── hammer.c ├── CMakeLists.txt ├── transport.h ├── msg.h ├── subscription.h ├── nail.c ├── bridge.c ├── zmqdefs.h ├── zmqbridgefunctions.h ├── SConscript ├── msg.c ├── subscription.c ├── publisher.c └── transport.c ├── config └── mama.properties ├── CMakeLists.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | .sconsign.dblite 7 | unittests 8 | hammer 9 | nail 10 | 11 | # Project files 12 | .cproject 13 | .project 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.os 29 | *.so.* 30 | *.dylib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | *.i*86 37 | *.x86_64 38 | *.hex 39 | 40 | # Debug files 41 | *.dSYM/ 42 | config.log 43 | build/ 44 | .sconf_temp/ 45 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright © 2015 Frank Quinn (http://fquinner.github.io) 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the “Software”), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | dist: bionic 3 | 4 | services: 5 | - docker 6 | 7 | notifications: 8 | webhooks: 9 | urls: 10 | - https://webhooks.gitter.im/e/1165d088c0b8da252a52 11 | on_success: always # options: [always|never|change] default: always 12 | on_failure: always # options: [always|never|change] default: always 13 | on_start: never # options: [always|never|change] default: always 14 | 15 | before_install: 16 | - sudo apt update -qq 17 | - curl -1sLf 'https://dl.cloudsmith.io/public/openmama/openmama/cfg/setup/bash.deb.sh' | sudo bash 18 | - sudo apt install -y openmama libgtest-dev 19 | 20 | script: 21 | - (mkdir gtest_bld && cd gtest_bld && cmake /usr/src/googletest/googletest -DCMAKE_INSTALL_PREFIX=/usr && sudo make install) 22 | - git clone https://github.com/OpenMAMA/OpenMAMA.git om_src 23 | - cmake -DOPENMAMA_SRC=$(pwd)/om_src -DCMAKE_INSTALL_PREFIX=$(pwd) . 24 | - make install 25 | - export LD_LIBRARY_PATH=/opt/openmama/lib:$(pwd)/lib 26 | - export WOMBAT_PATH=$(pwd)/config:$(pwd)/om_src/mama/c_cpp/src/gunittest/c/:$(pwd)/om_src/mama/c_cpp/src/examples 27 | - ./bin/UnitTestMamaC -m zmq -p qpidmsg -i Q 28 | - ./bin/UnitTestMamaMiddlewareC -m zmq -p qpidmsg -i Q 29 | 30 | after_script: 31 | - git clean -d -f -x 32 | - docker build -t openmama-zmq . 33 | - docker run -v $(pwd):/apps/src/bld --rm openmama-zmq -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7.5.1804 2 | 3 | # Run out-of-source builds 4 | WORKDIR /apps/src/bld 5 | 6 | # Install standard dependencies 7 | RUN yum install -y epel-release 8 | RUN yum install -y zeromq-devel curl cmake gcc gcc-c++ make libevent-devel libuuid-devel ruby-devel rpm-build 9 | 10 | ENV VERSION 1.2.3 11 | ENV DISTRIB_PACKAGE_QUALIFIER el7 12 | ENV PACKAGE_TYPE rpm 13 | 14 | # Install OpenMAMA 15 | RUN curl -1sLf 'https://dl.cloudsmith.io/public/openmama/openmama/cfg/setup/bash.rpm.sh' | bash 16 | # RUN curl -1sLf 'https://dl.cloudsmith.io/public/openmama/openmama/cfg/setup/bash.deb.sh' | bash 17 | RUN yum install -y openmama 18 | RUN gem install -N fpm 19 | 20 | # Add the rest of the source code here so code changes don't trigger dependency regeneration 21 | ADD . /apps/src 22 | 23 | # Perform the build and install 24 | RUN cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/apps/install/opt/openmama .. && make install 25 | 26 | RUN fpm -s dir \ 27 | -t $PACKAGE_TYPE \ 28 | -m "contact@cascadium.io" \ 29 | -C /apps/install \ 30 | --name openmama \ 31 | --version $VERSION \ 32 | --iteration 1 \ 33 | -d openmama -d zeromq -d libevent -d libuuid \ 34 | -p openmama-zmq-$VERSION-1.$DISTRIB_PACKAGE_QUALIFIER.x86_64.$PACKAGE_TYPE \ 35 | --description "OpenMAMA middleware bridge for zeromq" . 36 | 37 | # Copy the artifact to the release directory (probably mounted) 38 | CMD mkdir -p /apps/release && cp /opt/openmama/lib/libmamazmqimpl.so /apps/release 39 | -------------------------------------------------------------------------------- /SConstruct: -------------------------------------------------------------------------------- 1 | AddOption('--with-mamasource', 2 | default='/usr/local', 3 | dest='with_mamasource', 4 | type='string', 5 | nargs=1, 6 | action='store', 7 | metavar='DIR', 8 | help='Location of the uncompiled OpenMAMA Source code') 9 | 10 | AddOption('--with-mamainstall', 11 | default='/usr/local', 12 | dest='with_mamainstall', 13 | type='string', 14 | nargs=1, 15 | action='store', 16 | metavar='DIR', 17 | help='Location of OpenMAMA install') 18 | 19 | AddOption('--with-libevent', 20 | default='/usr/local', 21 | dest='with_libevent', 22 | type='string', 23 | nargs=1, 24 | action='store', 25 | metavar='DIR', 26 | help='Location of libevent install') 27 | 28 | AddOption('--with-zmq', 29 | default='/usr/local', 30 | dest='with_zmq', 31 | type='string', 32 | nargs=1, 33 | action='store', 34 | metavar='DIR', 35 | help='Location of zeromq install') 36 | 37 | AddOption('--target-arch', 38 | default=None, 39 | dest='target_arch', 40 | type='string', 41 | nargs=1, 42 | action='store', 43 | metavar='ARCH', 44 | help='Target architecture (x86 or x86_64)') 45 | 46 | AddOption('--build-type', 47 | default='dynamic', 48 | dest='build_type', 49 | type='string', 50 | nargs=1, 51 | action='store', 52 | metavar='TYPE', 53 | help='Build type [dynamic|dynamic-debug] (windows only)') 54 | 55 | SConscript('src/SConscript', variant_dir='objects/' + GetOption('build_type'), duplicate=0) 56 | -------------------------------------------------------------------------------- /src/hammer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | int main() 32 | { 33 | char buffer [223]; 34 | buffer[0] = 'A'; 35 | buffer[1] = '\0'; 36 | uint64_t* seq = (uint64_t*)(buffer + 2); 37 | uint32_t* s = (uint32_t*)(seq + 1); 38 | uint32_t* us = (uint32_t*)(s + 1); 39 | int i = 0; 40 | int j = 0; 41 | int hwm = 0; 42 | void* zmqSocketPublisher = zmq_socket (zmq_ctx_new (), ZMQ_PUB); 43 | zmq_setsockopt (zmqSocketPublisher, ZMQ_SNDHWM, &hwm, sizeof(int)); 44 | struct timeval tv; 45 | zmq_bind (zmqSocketPublisher, "tcp://*:5556"); 46 | *seq = 0; 47 | while (1) 48 | { 49 | (*seq)++; 50 | gettimeofday(&tv, NULL); 51 | *s = (uint32_t)tv.tv_sec; 52 | *us = (uint32_t)tv.tv_usec; 53 | 54 | int i = zmq_send (zmqSocketPublisher, buffer, sizeof(buffer), 0); 55 | int e = errno; 56 | if (i == -1) 57 | printf ("ERROR FOUND: %d\n", e); 58 | //for (j = 0; j < 1000000; j++); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /config/mama.properties: -------------------------------------------------------------------------------- 1 | # This is where all messages will be published including requests 2 | mama.zmq.transport.pub.outgoing_url_0=tcp://*:5557 3 | # This is where all messages will be received including replies 4 | mama.zmq.transport.pub.incoming_url_0=tcp://*:5556 5 | 6 | # This is where all messages will be published including requests 7 | mama.zmq.transport.pub2.outgoing_url_0=tcp://*:5559 8 | # This is where all messages will be received including replies 9 | mama.zmq.transport.pub2.incoming_url_0=tcp://*:5558 10 | 11 | 12 | # This is where all messages will be published including requests 13 | mama.zmq.transport.sub.outgoing_url_0=tcp://localhost:5556 14 | # This is where all messages will be received including replies 15 | mama.zmq.transport.sub.incoming_url_0=tcp://localhost:5557 16 | # Message pool sizes for receive message buffers 17 | mama.zmq.transport.sub.msg_pool_size=1024 18 | mama.zmq.transport.sub.msg_node_size=4096 19 | 20 | 21 | # This is where all messages will be published including requests 22 | mama.zmq.transport.subdual.outgoing_url_0=tcp://localhost:5556 23 | # This is where all messages will be received including replies 24 | mama.zmq.transport.subdual.incoming_url_0=tcp://localhost:5557 25 | # Connect to additional publisher 'pub2' 26 | mama.zmq.transport.subdual.outgoing_url_1=tcp://localhost:5558 27 | mama.zmq.transport.subdual.incoming_url_1=tcp://localhost:5559 28 | 29 | 30 | # Ensure loopback is running multicast for these to work 31 | mama.zmq.transport.pub_pgm.outgoing_url_0=pgm://127.0.0.1;239.192.1.1:5657 32 | mama.zmq.transport.pub_pgm.incoming_url_0=pgm://127.0.0.1;239.192.1.1:5656 33 | 34 | mama.zmq.transport.sub_pgm.outgoing_url_0=pgm://127.0.0.1;239.192.1.1:5656 35 | mama.zmq.transport.sub_pgm.incoming_url_0=pgm://127.0.0.1;239.192.1.1:5657 36 | 37 | # Ensure loopback is running multicast for these to work 38 | mama.zmq.transport.pub_epgm.outgoing_url_0=epgm://127.0.0.1;239.192.1.1:5657 39 | mama.zmq.transport.pub_epgm.incoming_url_0=epgm://127.0.0.1;239.192.1.1:5656 40 | 41 | mama.zmq.transport.sub_epgm.outgoing_url_0=epgm://127.0.0.1;239.192.1.1:5656 42 | mama.zmq.transport.sub_epgm.incoming_url_0=epgm://127.0.0.1;239.192.1.1:5657 43 | 44 | # Note destination here must be writable 45 | mama.zmq.transport.pub_ipc.outgoing_url_0=ipc:///tmp/feeds_0 46 | mama.zmq.transport.pub_ipc.incoming_url_0=ipc:///tmp/req_0 47 | 48 | mama.zmq.transport.sub_ipc.outgoing_url_0=ipc:///tmp/req_0 49 | mama.zmq.transport.sub_ipc.incoming_url_0=ipc:///tmp/feeds_0 50 | 51 | 52 | # Uncomment to use omnmmsg 53 | #mama.payload.default=omnmmsg 54 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(.) 2 | include_directories(${MAMA_ROOT}/include) 3 | include_directories(${EVENT_ROOT}/include) 4 | include_directories(${ZMQ_ROOT}/include) 5 | 6 | link_directories(${MAMA_ROOT}/lib) 7 | link_directories(${MAMA_ROOT}/lib/dynamic) 8 | link_directories(${MAMA_ROOT}/lib/dynamic-debug) 9 | link_directories(${ZMQ_ROOT}/lib) 10 | link_directories(${EVENT_ROOT}/lib) 11 | 12 | add_definitions(-DBRIDGE -DMAMA_DLL -DOPENMAMA_INTEGRATION) 13 | 14 | if(WIN32) 15 | if (CMAKE_BUILD_TYPE MATCHES "Debug") 16 | set(MAMA_LIB_SUFFIX "mdd") 17 | else() 18 | set(MAMA_LIB_SUFFIX "md") 19 | endif() 20 | else() 21 | set(MAMA_LIB_SUFFIX "") 22 | endif() 23 | 24 | add_library(mamazmqimpl${MAMA_LIB_SUFFIX} 25 | MODULE bridge.c 26 | msg.c 27 | msg.h 28 | publisher.c 29 | subscription.c 30 | subscription.h 31 | transport.c 32 | transport.h 33 | zmqbridgefunctions.h 34 | zmqdefs.h) 35 | 36 | if(WIN32) 37 | target_link_libraries(mamazmqimpl${MAMA_LIB_SUFFIX} 38 | libwombatcommon${MAMA_LIB_SUFFIX} 39 | libmamac${MAMA_LIB_SUFFIX} 40 | libzmq-v120-mt-4_0_4 41 | event 42 | uuid 43 | Ws2_32) 44 | 45 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 46 | set_target_properties(mamazmqimpl${MAMA_LIB_SUFFIX} PROPERTIES PREFIX "lib") 47 | 48 | # Windows Targets 49 | install(TARGETS mamazmqimpl${MAMA_LIB_SUFFIX} 50 | CONFIGURATIONS Release 51 | DESTINATION bin/dynamic) 52 | install(TARGETS mamazmqimpl${MAMA_LIB_SUFFIX} 53 | CONFIGURATIONS Debug 54 | DESTINATION bin/dynamic-debug) 55 | elseif(UNIX) 56 | target_link_libraries(mamazmqimpl${MAMA_LIB_SUFFIX} 57 | mamabaseimpl${MAMA_LIB_SUFFIX} 58 | wombatcommon 59 | mama 60 | zmq 61 | uuid 62 | event) 63 | install(TARGETS mamazmqimpl${MAMA_LIB_SUFFIX} DESTINATION lib) 64 | endif() 65 | 66 | # Default to installing directly to MAMA directory unless provided already 67 | if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 68 | set (CMAKE_INSTALL_PREFIX "${MAMA_ROOT}" CACHE PATH "default install path" FORCE) 69 | endif() 70 | -------------------------------------------------------------------------------- /src/transport.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef MAMA_BRIDGE_ZMQ_TRANSPORT_H__ 26 | #define MAMA_BRIDGE_ZMQ_TRANSPORT_H__ 27 | 28 | 29 | /*========================================================================= 30 | = Includes = 31 | =========================================================================*/ 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | #include "zmqdefs.h" 38 | 39 | #if defined(__cplusplus) 40 | extern "C" { 41 | #endif 42 | 43 | /** 44 | * This is a simple convenience function to return a zmqTransportBridge 45 | * pointer based on the provided mamaTransport. 46 | * 47 | * @param transport The mamaTransport to extract the bridge transport from. 48 | * 49 | * @return zmqTransportBridge* associated with the mamaTransport. 50 | */ 51 | zmqTransportBridge* 52 | zmqBridgeMamaTransportImpl_getTransportBridge (mamaTransport transport); 53 | 54 | /** 55 | * This is purely a debug function to dump to screen a snapshot of the status 56 | * of the transport's message pool. 57 | * 58 | * @param impl The zmq transport bridge referring to a message pool. 59 | */ 60 | void 61 | zmqBridgeMamaTransportImpl_dumpMessagePool (zmqTransportBridge* impl); 62 | 63 | #if defined(__cplusplus) 64 | } 65 | #endif 66 | 67 | #endif /* MAMA_BRIDGE_ZMQ_TRANSPORT_H__*/ 68 | -------------------------------------------------------------------------------- /src/msg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef MAMA_BRIDGE_ZMQ_MSG_H__ 26 | #define MAMA_BRIDGE_ZMQ_MSG_H__ 27 | 28 | 29 | /*========================================================================= 30 | = Includes = 31 | =========================================================================*/ 32 | 33 | #include "zmqdefs.h" 34 | #include 35 | 36 | 37 | #if defined(__cplusplus) 38 | extern "C" { 39 | #endif 40 | 41 | 42 | /*========================================================================= 43 | = Public implementation functions = 44 | =========================================================================*/ 45 | 46 | mama_status 47 | zmqBridgeMamaMsgImpl_serialize (msgBridge msg, 48 | mamaMsg source, 49 | void** target, 50 | size_t* size); 51 | 52 | mama_status 53 | zmqBridgeMamaMsgImpl_deserialize (msgBridge msg, 54 | const void* source, 55 | mama_size_t size, 56 | mamaMsg target); 57 | #if defined(__cplusplus) 58 | } 59 | #endif 60 | 61 | #endif /* MAMA_BRIDGE_ZMQ_MSG_H__ */ 62 | -------------------------------------------------------------------------------- /src/subscription.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef MAMA_BRIDGE_ZMQ_SUBSCRIPTION_H__ 26 | #define MAMA_BRIDGE_ZMQ_SUBSCRIPTION_H__ 27 | 28 | #if defined(__cplusplus) 29 | extern "C" { 30 | #endif 31 | 32 | /*========================================================================= 33 | = Public implementation functions = 34 | =========================================================================*/ 35 | 36 | /** 37 | * This function will generate a string which is unique to the root, source 38 | * and topic provided. Centralization of this function means that it can be used 39 | * in both the publisher and the subscriber in order to generate a consistent 40 | * topic for use throughout the platform. 41 | * 42 | * @param root Prefix to associate with the subject (e.g. _MDDD) 43 | * @param inbox Source to base the subject key on (e.g. EXCHANGENAME). 44 | * @param topic Topic to base the subject key on (e.g. ISIN.CURRENCY). 45 | * @param keyTarget Pointer to populate with the generated subject key. 46 | * 47 | * @return mama_status indicating whether the method succeeded or failed. 48 | */ 49 | mama_status 50 | zmqBridgeMamaSubscriptionImpl_generateSubjectKey (const char* root, 51 | const char* source, 52 | const char* topic, 53 | char** keyTarget); 54 | 55 | #if defined(__cplusplus) 56 | } 57 | #endif 58 | 59 | #endif /* MAMA_BRIDGE_ZMQ_SUBSCRIPTION_H__ */ 60 | -------------------------------------------------------------------------------- /src/nail.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | int main() 33 | { 34 | char buffer [223]; 35 | void* zmqSocketSubscriber = zmq_socket (zmq_ctx_new (), ZMQ_SUB); 36 | zmq_connect (zmqSocketSubscriber, "tcp://localhost:5556"); 37 | uint64_t* seq = 0; 38 | uint32_t* s = 0; 39 | uint32_t* us = 0; 40 | uint32_t s_last = 0; 41 | uint64_t msg_count = 0; 42 | int hwm = 0; 43 | struct timeval tv; 44 | zmq_setsockopt (zmqSocketSubscriber, ZMQ_RCVHWM, &hwm, sizeof(int)); 45 | 46 | zmq_setsockopt (zmqSocketSubscriber, ZMQ_SUBSCRIBE, "A", 1); 47 | uint64_t expectedSeq = 1; 48 | while (1) 49 | { 50 | int size = zmq_recv (zmqSocketSubscriber, buffer, sizeof(buffer), 0); 51 | int e = errno; 52 | if (size == -1) 53 | printf ("ERROR FOUND: %d\n", e); 54 | uint8_t* copy = calloc (1, size); 55 | memcpy (copy, buffer, size); 56 | memcmp (copy, buffer, size); 57 | msg_count++; 58 | seq = (uint64_t*)(buffer + 2); 59 | s = (uint32_t*)(seq + 1); 60 | us = (uint32_t*)(s + 1); 61 | gettimeofday (&tv, NULL); 62 | 63 | if ((uint32_t)tv.tv_sec != s_last) 64 | { 65 | printf ("Seconds = %lu; msgs = %lu;\n", *s, msg_count); 66 | s_last = (uint32_t)tv.tv_sec; 67 | msg_count = 0; 68 | } 69 | if (*seq != expectedSeq) 70 | { 71 | printf ("Gap from %lu to %lu observed\n", expectedSeq, *seq); 72 | expectedSeq = *seq; 73 | } 74 | expectedSeq++; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8.7) 2 | project (OpenMAMA-zmq) 3 | 4 | if(UNIX) 5 | if(MAMA_ROOT) 6 | set(DEFAULT_INSTALL_PREFIX $MAMA_ROOT/lib) 7 | endif() 8 | set(DEFAULT_MAMA_ROOT "/opt/openmama") 9 | else() 10 | if(CMAKE_CL_64) 11 | set(DEFAULT_INSTALL_PREFIX $ENV{ProgramW6432}) 12 | else() 13 | set(DEFAULT_INSTALL_PREFIX $ENV{PROGRAMFILES}) 14 | endif() 15 | 16 | # Note path is relative to where it would be used 17 | set(DEFAULT_MAMA_ROOT "${DEFAULT_INSTALL_PREFIX}/OpenMAMA") 18 | set(DEFAULT_ZMQ_ROOT "${DEFAULT_INSTALL_PREFIX}/ZeroMQ 4.0.4") 19 | set(DEFAULT_EVENT_ROOT "${DEFAULT_INSTALL_PREFIX}/libevent") 20 | endif() 21 | 22 | if(NOT MAMA_ROOT) 23 | set(MAMA_ROOT ${DEFAULT_MAMA_ROOT}) 24 | endif() 25 | 26 | if(NOT ZMQ_ROOT) 27 | set(ZMQ_ROOT ${DEFAULT_ZMQ_ROOT}) 28 | endif() 29 | 30 | if(NOT EVENT_ROOT) 31 | set(EVENT_ROOT ${DEFAULT_EVENT_ROOT}) 32 | endif() 33 | 34 | add_subdirectory(src) 35 | 36 | if(OPENMAMA_SRC) 37 | include_directories(${MAMA_ROOT}/include) 38 | include_directories(${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c) 39 | include_directories(${OPENMAMA_SRC}/mama/c_cpp/src/c) 40 | link_directories(${MAMA_ROOT}/lib) 41 | link_directories(${GTEST_ROOT}/lib) 42 | 43 | add_executable(UnitTestMamaC 44 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/MainUnitTestC.cpp 45 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/inboxtest.cpp 46 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/iotest.cpp 47 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/mamainternaltest.cpp 48 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/msgutils.cpp 49 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/openclosetest.cpp 50 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/publishertest.cpp 51 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/queuetest.cpp 52 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/dictionarytest.cpp 53 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/subscriptiontest.cpp 54 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/timertest.cpp 55 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/transporttest.cpp 56 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/fieldcache/fieldcachevectortest.cpp 57 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/fieldcache/fieldcachelisttest.cpp 58 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/fieldcache/fieldcachemaptest.cpp 59 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/fieldcache/fieldcachefieldtest.cpp 60 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/fieldcache/fieldcacheiteratortest.cpp 61 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/fieldcache/fieldcacherecordtest.cpp 62 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/fieldcache/fieldcachetest.cpp 63 | ) 64 | target_link_libraries(UnitTestMamaC mama gtest pthread wombatcommon) 65 | install(TARGETS UnitTestMamaC DESTINATION bin) 66 | 67 | add_executable(UnitTestMamaMiddlewareC 68 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/MainUnitTestC.cpp 69 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/middleware/middlewareGeneralTests.cpp 70 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/middleware/middlewareInboxTests.cpp 71 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/middleware/middlewareIoTests.cpp 72 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/middleware/middlewareMsgTests.cpp 73 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/middleware/middlewarePublisherTests.cpp 74 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/middleware/middlewareQueueTests.cpp 75 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/middleware/middlewareSubscriptionTests.cpp 76 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/middleware/middlewareTimerTests.cpp 77 | ${OPENMAMA_SRC}/mama/c_cpp/src/gunittest/c/middleware/middlewareTransportTests.cpp 78 | ) 79 | target_link_libraries(UnitTestMamaMiddlewareC mama gtest pthread wombatcommon) 80 | install(TARGETS UnitTestMamaMiddlewareC DESTINATION bin) 81 | else() 82 | message(WARNING "If you want full unit tests, you should provide -DOPENMAMA_SRC=") 83 | endif() 84 | -------------------------------------------------------------------------------- /src/bridge.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | /*========================================================================= 26 | = Includes = 27 | =========================================================================*/ 28 | 29 | #include 30 | #include 31 | #include 32 | #include "zmqbridgefunctions.h" 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | /*========================================================================= 39 | = Typedefs, structs, enums and globals = 40 | =========================================================================*/ 41 | 42 | /* Default payload names and IDs to be loaded when this bridge is loaded */ 43 | static char* PAYLOAD_NAMES[] = { "qpidmsg", NULL }; 44 | static char PAYLOAD_IDS[] = { MAMA_PAYLOAD_QPID, '\0' }; 45 | 46 | /*========================================================================= 47 | = Macros = 48 | =========================================================================*/ 49 | 50 | /* Version identifiers */ 51 | #define BRIDGE_NAME "zmq" 52 | #define BRIDGE_VERSION "1.0" 53 | 54 | 55 | /*========================================================================= 56 | = Public interface implementation functions = 57 | =========================================================================*/ 58 | 59 | mama_status 60 | zmqBridge_init (mamaBridge bridgeImpl) 61 | { 62 | mama_status status = MAMA_STATUS_OK; 63 | const char* runtimeVersion = NULL; 64 | 65 | /* Reusable buffer to populate with property values */ 66 | char propString[MAX_INTERNAL_PROP_LEN]; 67 | versionInfo rtVer; 68 | 69 | mama_log (MAMA_LOG_LEVEL_SEVERE, "noopBridge_init(): IN INIT"); 70 | 71 | /* Will set the bridge's compile time MAMA version */ 72 | MAMA_SET_BRIDGE_COMPILE_TIME_VERSION(BRIDGE_NAME); 73 | 74 | /* Enable extending of the base bridge implementation */ 75 | status = mamaBridgeImpl_setReadOnlyProperty (bridgeImpl, 76 | MAMA_PROP_EXTENDS_BASE_BRIDGE, 77 | "true"); 78 | 79 | /* Get the runtime version of MAMA and parse into version struct */ 80 | runtimeVersion = mamaInternal_getMetaProperty (MAMA_PROP_MAMA_RUNTIME_VER); 81 | strToVersionInfo (runtimeVersion, &rtVer); 82 | 83 | return MAMA_STATUS_OK; 84 | } 85 | 86 | const char* 87 | zmqBridge_getVersion (void) 88 | { 89 | return BRIDGE_VERSION; 90 | } 91 | 92 | const char* 93 | zmqBridge_getName (void) 94 | { 95 | return BRIDGE_NAME; 96 | } 97 | 98 | mama_status 99 | zmqBridge_getDefaultPayloadId (char ***name, char **id) 100 | { 101 | if (NULL == name || NULL == id) 102 | { 103 | return MAMA_STATUS_NULL_ARG; 104 | } 105 | /* 106 | * Populate name with the value of all supported payload names, the first 107 | * being the default 108 | */ 109 | *name = PAYLOAD_NAMES; 110 | 111 | /* 112 | * Populate id with the char keys for all supported payload names, the first 113 | * being the default 114 | */ 115 | *id = PAYLOAD_IDS; 116 | 117 | return MAMA_STATUS_OK; 118 | } 119 | -------------------------------------------------------------------------------- /src/zmqdefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef MAMA_BRIDGE_ZMQ_ZMQDEFS_H__ 26 | #define MAMA_BRIDGE_ZMQ_ZMQDEFS_H__ 27 | 28 | 29 | /*========================================================================= 30 | = Includes = 31 | =========================================================================*/ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #if defined(__cplusplus) 42 | extern "C" { 43 | #endif 44 | 45 | 46 | /*========================================================================= 47 | = Macros = 48 | =========================================================================*/ 49 | 50 | /* Maximum topic length */ 51 | #define MAX_SUBJECT_LENGTH 256 52 | #define ZMQ_MAX_INCOMING_URIS 64 53 | #define ZMQ_MAX_OUTGOING_URIS 64 54 | 55 | typedef enum zmqTransportType_ 56 | { 57 | ZMQ_TPORT_TYPE_TCP, 58 | ZMQ_TPORT_TYPE_IPC, 59 | ZMQ_TPORT_TYPE_PGM, 60 | ZMQ_TPORT_TYPE_EPGM, 61 | ZMQ_TPORT_TYPE_UNKNOWN = 99 62 | } zmqTransportType; 63 | 64 | typedef enum zmqTransportDirection_ 65 | { 66 | ZMQ_TPORT_DIRECTION_INCOMING, 67 | ZMQ_TPORT_DIRECTION_OUTGOING 68 | } zmqTransportDirection; 69 | 70 | 71 | /*========================================================================= 72 | = Typedefs, structs, enums and globals = 73 | =========================================================================*/ 74 | 75 | typedef struct zmqTransportBridge_ 76 | { 77 | int mIsValid; 78 | mamaTransport mTransport; 79 | msgBridge mMsg; 80 | void* mZmqContext; 81 | void* mZmqSocketSubscriber; 82 | void* mZmqSocketPublisher; 83 | void* mZmqSocketDispatcher; 84 | const char* mIncomingAddress[ZMQ_MAX_INCOMING_URIS]; 85 | const char* mOutgoingAddress[ZMQ_MAX_OUTGOING_URIS]; 86 | const char* mName; 87 | wthread_t mOmzmqDispatchThread; 88 | int mIsDispatching; 89 | mama_status mOmzmqDispatchStatus; 90 | endpointPool_t mSubEndpoints; 91 | endpointPool_t mPubEndpoints; 92 | long int mMemoryPoolSize; 93 | long int mMemoryNodeSize; 94 | } zmqTransportBridge; 95 | 96 | typedef struct zmqSubscription_ 97 | { 98 | mamaMsgCallbacks mMamaCallback; 99 | mamaSubscription mMamaSubscription; 100 | mamaQueue mMamaQueue; 101 | void* mZmqQueue; 102 | zmqTransportBridge* mTransport; 103 | const char* mSymbol; 104 | char* mSubjectKey; 105 | void* mClosure; 106 | int mIsNotMuted; 107 | int mIsValid; 108 | int mIsTportDisconnected; 109 | msgBridge mMsg; 110 | const char* mEndpointIdentifier; 111 | } zmqSubscription; 112 | 113 | typedef struct zmqTransportMsg_ 114 | { 115 | size_t mNodeSize; 116 | size_t mNodeCapacity; 117 | zmqSubscription* mSubscription; 118 | uint8_t* mNodeBuffer; 119 | } zmqTransportMsg; 120 | 121 | typedef struct zmqQueueBridge { 122 | mamaQueue mParent; 123 | wombatQueue mQueue; 124 | void* mEnqueueClosure; 125 | uint8_t mHighWaterFired; 126 | size_t mHighWatermark; 127 | size_t mLowWatermark; 128 | uint8_t mIsDispatching; 129 | mamaQueueEnqueueCB mEnqueueCallback; 130 | void* mClosure; 131 | wthread_mutex_t mDispatchLock; 132 | void* mZmqContext; 133 | void* mZmqSocketWorker; 134 | void* mZmqSocketDealer; 135 | } zmqQueueBridge; 136 | 137 | 138 | #if defined(__cplusplus) 139 | } 140 | #endif 141 | 142 | #endif /* MAMA_BRIDGE_ZMQ_ZMQDEFS_H__ */ 143 | -------------------------------------------------------------------------------- /src/zmqbridgefunctions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef ZMQ_BRIDGE_FUNCTIONS__ 26 | #define ZMQ_BRIDGE_FUNCTIONS__ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #if defined(__cplusplus) 38 | extern "C" { 39 | #endif 40 | 41 | MAMAExpBridgeDLL 42 | extern mama_status 43 | zmqBridge_init (mamaBridge bridgeImpl); 44 | 45 | MAMAExpBridgeDLL 46 | extern const char* 47 | zmqBridge_getVersion (void); 48 | 49 | MAMAExpBridgeDLL 50 | extern const char* 51 | zmqBridge_getName (void); 52 | 53 | MAMAExpBridgeDLL 54 | extern mama_status 55 | zmqBridge_getDefaultPayloadId (char*** name, char** id); 56 | 57 | MAMAExpBridgeDLL 58 | extern int 59 | zmqBridgeMamaTransport_isValid (transportBridge transport); 60 | 61 | MAMAExpBridgeDLL 62 | extern mama_status 63 | zmqBridgeMamaTransport_destroy (transportBridge transport); 64 | 65 | MAMAExpBridgeDLL 66 | extern mama_status 67 | zmqBridgeMamaTransport_create (transportBridge* result, 68 | const char* name, 69 | mamaTransport parent); 70 | 71 | MAMAExpBridgeDLL 72 | extern mama_status zmqBridgeMamaSubscription_create 73 | (subscriptionBridge* subscriber, 74 | const char* source, 75 | const char* symbol, 76 | mamaTransport transport, 77 | mamaQueue queue, 78 | mamaMsgCallbacks callback, 79 | mamaSubscription subscription, 80 | void* closure ); 81 | 82 | 83 | MAMAExpBridgeDLL 84 | extern mama_status 85 | zmqBridgeMamaSubscription_mute (subscriptionBridge subscriber); 86 | 87 | MAMAExpBridgeDLL 88 | extern mama_status 89 | zmqBridgeMamaSubscription_destroy (subscriptionBridge subscriber); 90 | 91 | MAMAExpBridgeDLL 92 | extern int 93 | zmqBridgeMamaSubscription_isValid (subscriptionBridge bridge); 94 | 95 | MAMAExpBridgeDLL 96 | extern int 97 | zmqBridgeMamaSubscription_isTportDisconnected (subscriptionBridge subsc); 98 | 99 | MAMAExpBridgeDLL 100 | extern mama_status 101 | zmqBridgeMamaSubscription_muteCurrentTopic (subscriptionBridge subsc); 102 | 103 | MAMAExpBridgeDLL 104 | extern mama_status 105 | zmqBridgeMamaPublisher_createByIndex ( 106 | publisherBridge* result, 107 | mamaTransport tport, 108 | int tportIndex, 109 | const char* topic, 110 | const char* source, 111 | const char* root, 112 | mamaPublisher parent); 113 | 114 | MAMAExpBridgeDLL 115 | extern mama_status 116 | zmqBridgeMamaPublisher_destroy (publisherBridge publisher); 117 | 118 | MAMAExpBridgeDLL 119 | extern mama_status 120 | zmqBridgeMamaPublisher_send (publisherBridge publisher, mamaMsg msg); 121 | 122 | MAMAExpBridgeDLL 123 | extern mama_status 124 | zmqBridgeMamaPublisher_sendReplyToInbox (publisherBridge publisher, 125 | void* request, 126 | mamaMsg reply); 127 | 128 | MAMAExpBridgeDLL 129 | extern mama_status 130 | zmqBridgeMamaPublisher_sendReplyToInboxHandle (publisherBridge publisher, 131 | void* wmwReply, 132 | mamaMsg reply); 133 | 134 | MAMAExpBridgeDLL 135 | extern mama_status 136 | zmqBridgeMamaPublisher_sendFromInbox (publisherBridge publisher, 137 | mamaInbox inbox, 138 | mamaMsg msg); 139 | 140 | MAMAExpBridgeDLL 141 | extern mama_status 142 | zmqBridgeMamaPublisher_sendFromInboxByIndex (publisherBridge publisher, 143 | int tportIndex, 144 | mamaInbox inbox, 145 | mamaMsg msg); 146 | 147 | MAMAExpBridgeDLL 148 | extern mama_status 149 | zmqBridgeMamaPublisher_setUserCallbacks (publisherBridge publisher, 150 | mamaQueue queue, 151 | mamaPublisherCallbacks* cb, 152 | void* closure); 153 | 154 | #if defined(__cplusplus) 155 | } 156 | #endif 157 | 158 | #endif /*ZMQ_BRIDGE_FUNCTIONS__*/ 159 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This Repository is No Longer Maintained 2 | 3 | There is a fork of this project now actively maintained at [https://github.com/nyfix/OZ](https://github.com/nyfix/OZ). Please refer to that repository for future releases. This repository remains only for reference. 4 | 5 | # OpenMAMA ZeroMQ Middleware Bridge 6 | 7 | [![Join the chat at https://gitter.im/fquinner/OpenMAMA-zmq](https://badges.gitter.im/fquinner/OpenMAMA-zmq.svg)](https://gitter.im/fquinner/OpenMAMA-zmq?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 8 | [![Build Status](https://travis-ci.org/fquinner/OpenMAMA-zmq.svg?branch=master)](https://travis-ci.org/fquinner/OpenMAMA-zmq) 9 | 10 | ## Functionality 11 | 12 | This project now has complete MAMA middleware bridge functionality. 13 | It passes all of the OpenMAMA middleware unit tests and provides: 14 | 15 | * Support for point to point, fan-in and fan-out messaging 16 | * Support for **any** serializable / deserializable MAMA Message payload bridge 17 | * Significant performance improvement over qpid 18 | * Request / Reply Functionality 19 | * Basic Publish / Subscribe 20 | * Market Data Publish / Subscribe 21 | * ZeroMQ TCP transport compatibility 22 | * ZeroMQ PGM (multicast) transport compatibility 23 | * ZeroMQ IPC (named pipes) transport compatibility 24 | 25 | You can expect the pub / sub / request / reply example apps to work great out 26 | of the box including: 27 | 28 | * mamapublisherc / mamasubscriberc 29 | * mamapublisherc / mamainboxc 30 | * capturereplayc / mamalistenc 31 | 32 | ## Releases 33 | 34 | We now provide binary releases - see 35 | https://github.com/fquinner/OpenMAMA-zmq/releases for a list of binaries 36 | available. If we have missed a platform that you are using, please let us 37 | know. 38 | 39 | ## Usage Instructions 40 | 41 | ### Linux 42 | After building or grabbing a binary release, you will have a 43 | `libmamazmqimpl.so` file created. Add the 44 | directory containing this library to the `LD_LIBRARY_PATH` environment 45 | variable and run your applications with `-m zmq` to use the bridge. 46 | 47 | ### Windows 48 | After building or grabbing a binary release, you will have a 49 | `libmamazmqimplmd.dll` file created. Add the directory containing this 50 | library to the `PATH` environment variable or add it to the executable's 51 | directory to allow it to load and run your applications with `-m zmq` to 52 | use the bridge. 53 | 54 | ### Setting up a transport 55 | 56 | Check out the [mama.properties](config/mama.properties) file for details on 57 | the various transport options available and how to set them up. 58 | You can also use a forwarder as 59 | detailed [here](http://fquinner.github.io/2015/12/05/openmama-and-zeromq-fanout/). 60 | 61 | It's worth mentioning you can also override selected zmq socket settings 62 | directly as listed in the configuration table below. 63 | 64 | You may set a configuration parameter by setting `mama.zmq.transport..` 65 | either programatically or through `mama.properties` where `setting` is one of the 66 | parameters listed below. 67 | 68 | |Configuration Setting|Brief Description|Default Value in Bridge| 69 | |---|---|---| 70 | |msg_pool_size|Number of elements to store in the transport's message pool|1024| 71 | |msg_node_size|Initial size of each memory node in the transport's message pool|4096 72 | |outgoing_url_0, outgoing_url_1 .. outgoing_url_N|Multiple URLs to send all publisher messages to including published data and subscription requests (see ZMQ URI documentation)|'tcp://\*:5557' if transport name is 'sub', 'tcp://*:5556' if transport name is 'pub'| 73 | |incoming_url_0, incoming_url_1 .. incoming_url_N|Multiple URLs to receive messages from including subscription data and replies (see ZMQ URI documentation)|'tcp://127.0.0.1:5556' if transport name is 'sub', 'tcp://127.0.0.1:5557' if transport name is 'pub'| 74 | |zmq_sndhwm|High watermark for outbound messages|0 (Unlimited)| 75 | |zmq_rcvhwm|High watermark for inbound messages|0 (Unlimited)| 76 | |zmq_identity|Socket identifier|NULL| 77 | |zmq_affinity|Set I/O thread affinity (bitmap)|0 (Unbinded)| 78 | |zmq_sndbuf|Kernel transmit buffer size|OS Default| 79 | |zmq_rcvbuf|Kernel receive buffer size|OS Default| 80 | |zmq_reconnect_ivl|Reconnection interval (milliseconds)|100| 81 | |zmq_reconnect_ivl_max|Maximum reconnection interval during exponential backoff policy|0 (Only use reconnection interval ad infinum)| 82 | |zmq_backlog|Maximum length of the queue of outstanding connections|100| 83 | |zmq_maxmsgsize|Maximum message size to be transferred|-1 (Unlimited)| 84 | |zmq_rcvtimeo|Maximum time before a recv operation returns with EAGAIN (milliseconds)|10| 85 | |zmq_sndtimeo|Maximum time before a send operation returns with EAGAIN (milliseconds)|-1 (Unlimited)| 86 | |zmq_rate|Maximum multicast data rate (kbps)|1,000,000| 87 | 88 | Note that any settings made here will apply to all sockets that are created 89 | by the transport. For more details on the parameters beginning with `zmq_`, please 90 | refer to the [ZeroMW socket option documentation](http://api.zeromq.org/4-0:zmq-setsockopt). 91 | 92 | ## Payload Selection 93 | 94 | This middleware bridge uses the qpid payload bridge by default. If you want 95 | to use the omnm payload (less functionality but _much_ faster than qpid), 96 | you can have a look at [the omnm github page](https://github.com/fquinner/OpenMAMA-omnm) to find 97 | to see what's involved. 98 | 99 | ## Build Instructions 100 | 101 | ### Supported Platforms 102 | 103 | * RHEL / CentOS 104 | * Fedora 105 | * Ubuntu 106 | * Windows 107 | 108 | ### Dependencies 109 | 110 | The bridge depends on: 111 | 112 | * MAMA / OpenMAMA (2.4.0+ / 6.0.7+ / 6.1.x) 113 | * Libevent (1.x) 114 | * Scons (will also require Python) 115 | * Libuuid (only on Linux) 116 | 117 | ### Building 118 | 119 | If you have all the prerequisites, the build process should be pretty 120 | straightforward: 121 | 122 | scons --with-mamasource=PATH --with-mamainstall=PATH 123 | 124 | ## Project Goals 125 | 126 | This ethos of this project is to: 127 | 128 | * Create a fully functional ZeroMQ bridge which introduces minimal latency and 129 | maximum throughput when compared with a native ZeroMQ implementation. 130 | * Create a bridge which is fully conformant with the latest OpenMAMA acceptance 131 | and unit tests. 132 | * Give anything which would be useful for 'any old middleware bridge' back to 133 | the OpenMAMA core project. 134 | 135 | *NB: This project is MIT Licensed and in no way affiliated with nor supported 136 | by the OpenMAMA project or SR Labs - if you find any issues, please report to 137 | this project via github.* 138 | 139 | ## Related Projects 140 | 141 | * [OpenMAMA](http://openmama.org) 142 | * [ZeroMQ](http://zeromq.org) 143 | * [OpenMAMA Native Message (OMNM)](https://github.com/fquinner/OpenMAMA-omnm) 144 | 145 | ## Blog 146 | 147 | If you're interested in the thought process behind this or the ramblings of the 148 | author, you can shoot on over to [my blog page](http://fquinner.github.io). 149 | -------------------------------------------------------------------------------- /src/SConscript: -------------------------------------------------------------------------------- 1 | import glob 2 | import os 3 | 4 | env = Environment ( 5 | WITH_MAMA_SOURCE = GetOption('with_mamasource'), 6 | WITH_MAMA = GetOption('with_mamainstall'), 7 | WITH_LIBEVENT = GetOption('with_libevent'), 8 | WITH_ZMQ = GetOption('with_zmq'), 9 | TARGET_ARCH = GetOption('target_arch'), 10 | BUILD_TYPE = GetOption('build_type'), 11 | SHLIBPREFIX = 'lib', 12 | suffix = '', 13 | CPPPATH = [ 14 | './src', 15 | '$WITH_MAMA_SOURCE/common/c_cpp/src/c', 16 | '$WITH_MAMA_SOURCE/mama/c_cpp/src/c', 17 | '$WITH_MAMA_SOURCE/mama/c_cpp/src/c/bridge/qpid', 18 | '$WITH_MAMA/include', 19 | '$WITH_LIBEVENT/include', 20 | '$WITH_ZMQ/include', 21 | ], 22 | ) 23 | 24 | # Windows has a few differences 25 | if env['PLATFORM'] == "win32": 26 | if env['BUILD_TYPE'] == 'dynamic' or env['BUILD_TYPE'] == None: 27 | env.Append( 28 | CCFLAGS = ['/MD','/Ox'], 29 | suffix = 'md', 30 | ) 31 | elif env['BUILD_TYPE'] == 'dynamic-debug': 32 | env.Append( 33 | CCFLAGS = ['/MDd'], 34 | suffix = 'mdd', 35 | ) 36 | else: 37 | print "Unknown build type specified - exiting" 38 | Exit(1) 39 | 40 | zmq_ver_abbrev = int(env['MSVC_VERSION'][:4].replace ('.', '')) 41 | 42 | zmq_match = [] 43 | zmq_lib = '' 44 | # 9.0 is earliest supported MSVC version for ZeroMQ 45 | while zmq_ver_abbrev >= 90 and len(zmq_match) == 0: 46 | zmq_match = glob.glob (env['WITH_ZMQ'] + '/lib/' + 'libzmq-v' + 47 | str(zmq_ver_abbrev) + '-mt-*.lib') 48 | zmq_ver_abbrev -= 10 49 | if len(zmq_match) > 0: 50 | # Should be two matches - second is debug 51 | if not env['BUILD_TYPE'].endswith('debug'): 52 | zmq_lib = os.path.basename(zmq_match[0]).replace ('.lib', '') 53 | else: 54 | zmq_lib = os.path.basename(zmq_match[1]).replace ('.lib', '') 55 | elif not env.GetOption('clean') and not env.GetOption('help'): 56 | print "Couldn't find any zeromq libraries! Check %s" % env['WITH_ZMQ'] 57 | Exit (1) 58 | 59 | env.Append ( 60 | LIBS = [ 61 | 'libmamac' + env['suffix'], 62 | 'uuid', 63 | 'Ws2_32', 64 | 'libevent', 65 | 'libwombatcommon' + env['suffix'], 66 | zmq_lib, 67 | ], 68 | LIBPATH = [ 69 | '$WITH_MAMA/lib/' + env['BUILD_TYPE'], 70 | '$WITH_ZMQ/lib', 71 | '.', 72 | ], 73 | CPPFLAGS = [ 74 | '/DMAMA_DLL', 75 | ], 76 | ) 77 | env['CPPPATH'].append([ 78 | '$WITH_LIBEVENT/WIN32-Code', 79 | '$WITH_LIBEVENT/', 80 | '$WITH_MAMA_SOURCE/common/c_cpp/src/c/windows', 81 | ]) 82 | if 'x86_64' == env['TARGET_ARCH']: 83 | env['LIBPATH'].append(['$WITH_LIBEVENT/WIN32-Prj/x64/Release']) 84 | else: 85 | env['LIBPATH'].append(['$WITH_LIBEVENT/WIN32-Prj/Release']) 86 | 87 | if not env.GetOption('clean') and not env.GetOption('help'): 88 | conf = Configure (env) 89 | 90 | # Internal MAMA header 91 | if not conf.CheckCHeader ('bridge.h'): 92 | print 'Cannot find MAMA Source code - check --with-mamasource' 93 | Exit(1) 94 | 95 | # Scons preprocessor doesn't understand this file, so just check it 96 | # exists 97 | if not FindFile('event.h', env['WITH_LIBEVENT']): 98 | print 'Cannot find event.h - ensure libevent devel is installed' 99 | Exit(1) 100 | 101 | # Scons preprocessor doesn't understand this file, so just check it 102 | # exists 103 | if not FindFile('include/mama/mama.h', env['WITH_MAMA']): 104 | print 'Cannot find MAMA install directory - check --with-mamainstall' 105 | Exit(1) 106 | conf.Finish() 107 | elif env['PLATFORM'] == "posix": 108 | env.Append ( 109 | LIBS = [ 110 | 'mama', 111 | 'uuid', 112 | 'zmq', 113 | 'event', 114 | 'wombatcommon', 115 | 'pthread', 116 | ], 117 | LIBPATH = [ 118 | '$WITH_MAMA/lib', 119 | '$WITH_MAMA/lib64', 120 | '$WITH_LIBEVENT/lib', 121 | '$WITH_LIBEVENT/lib64', 122 | '$WITH_ZMQ/lib', 123 | '$WITH_ZMQ/lib64', 124 | '.', 125 | ], 126 | CFLAGS = [ 127 | '-g', 128 | '-O3' 129 | ], 130 | ) 131 | if not env.GetOption('clean') and not env.GetOption('help'): 132 | conf = Configure (env) 133 | if not conf.CheckCHeader ('bridge.h'): 134 | print 'Cannot find MAMA Source code - check --with-mamasource' 135 | Exit(1) 136 | 137 | if not conf.CheckCHeader ('uuid/uuid.h'): 138 | print 'Cannot find uuid - ensure uuid devel is installed' 139 | Exit(1) 140 | 141 | if not conf.CheckCHeader ('event.h'): 142 | print 'Cannot find event.h - ensure libevent devel is installed' 143 | Exit(1) 144 | 145 | if not conf.CheckLib ('mama'): 146 | print 'Cannot find MAMA install directory - check --with-mamainstall' 147 | Exit(1) 148 | conf.Finish() 149 | env.Program ('hammer', 'hammer.c') 150 | env.Program ('nail', 'nail.c') 151 | env.Program ('queuebench', 'queuebench.c') 152 | else: 153 | print "Unsupported platform: %s" % env['PLATFORM'] 154 | exit (1) 155 | 156 | env.Command ("endpointpool.c", 157 | "$WITH_MAMA_SOURCE/mama/c_cpp/src/c/bridge/qpid/endpointpool.c", 158 | [ 159 | Copy("$TARGET", "$SOURCE"), 160 | ] 161 | ) 162 | 163 | libs = env.SharedLibrary ( 164 | 'mamazmqimpl' + env['suffix'], 165 | [ 166 | 'bridge.c', 167 | 'endpointpool.c', 168 | 'inbox.c', 169 | 'io.c', 170 | 'msg.c', 171 | 'publisher.c', 172 | 'queue.c', 173 | 'subscription.c', 174 | 'timer.c', 175 | 'transport.c' 176 | ] 177 | ) 178 | 179 | # Install the library to the top directory 180 | env.Command ("../../" + str(libs[0]), 181 | str(libs[0]), 182 | [ 183 | Copy("$TARGET", "$SOURCE"), 184 | ] 185 | ) 186 | 187 | -------------------------------------------------------------------------------- /src/msg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | /*========================================================================= 26 | = Includes = 27 | =========================================================================*/ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "transport.h" 34 | #include "msg.h" 35 | 36 | #include 37 | #include 38 | 39 | #include "zmqbridgefunctions.h" 40 | 41 | 42 | /*========================================================================= 43 | = Macros = 44 | =========================================================================*/ 45 | 46 | #define ZMQ_MSG_PROPERTY_LEN 1024 47 | 48 | 49 | /*========================================================================= 50 | = Public interface implementation functions = 51 | =========================================================================*/ 52 | 53 | mama_status 54 | zmqBridgeMamaMsgImpl_serialize (msgBridge msg, 55 | mamaMsg source, 56 | void** target, 57 | size_t* size) 58 | { 59 | mama_size_t msgSize = 0; 60 | const void* msgBuffer = NULL; 61 | char* sendSubject = NULL; 62 | char* targetSubject = NULL; 63 | char* replyInboxName = NULL; 64 | void* serializedBuffer = NULL; 65 | size_t serializedBufferSize = 0; 66 | mama_size_t payloadSize = 0; 67 | size_t msgSubjectByteCount = 0; 68 | size_t msgInboxByteCount = 0; 69 | //size_t msgReplyToByteCount = 0; 70 | size_t msgTargetSubjectByteCount = 0; 71 | size_t serializedSize = 0; 72 | baseMsgType msgType; 73 | 74 | // Serialize payload 75 | mama_status status = mamaMsg_getByteBuffer (source, &msgBuffer, &msgSize); 76 | 77 | // Gather required state from base bridge 78 | baseBridgeMamaMsgImpl_getSendSubject(msg, &sendSubject); 79 | baseBridgeMamaMsgImpl_getMsgType(msg, &msgType); 80 | baseBridgeMamaMsgImpl_getTargetSubject(msg, &targetSubject); 81 | baseBridgeMamaMsgImpl_getInboxName(msg, &replyInboxName); 82 | 83 | serializedSize = strlen(sendSubject) + 10 + msgSize; 84 | switch (msgType) 85 | { 86 | case BASE_MSG_INBOX_REQUEST: 87 | serializedSize += strlen (replyInboxName) + 1; 88 | break; 89 | case BASE_MSG_INBOX_RESPONSE: 90 | serializedSize += strlen (targetSubject) + 1; 91 | break; 92 | case BASE_MSG_SUB_REQUEST: 93 | case BASE_MSG_PUB_SUB: 94 | default: 95 | break; 96 | } 97 | 98 | status = baseBridgeMamaMsgImpl_getSerializationBuffer (msg, 99 | &serializedBuffer, 100 | serializedSize); 101 | if (MAMA_STATUS_OK != status) 102 | { 103 | mama_log (MAMA_LOG_LEVEL_ERROR, "Could not allocate serialization buffer"); 104 | return status; 105 | } 106 | 107 | // Ok great - we have a buffer now of appropriate size, let's populate it 108 | uint8_t* bufferPos = (uint8_t*)serializedBuffer; 109 | 110 | // Copy across the subject 111 | msgSubjectByteCount = strlen (sendSubject) + 1; 112 | memcpy (bufferPos, sendSubject, msgSubjectByteCount); 113 | bufferPos += msgSubjectByteCount; 114 | 115 | // Leave 8 bytes empty - receive side will be thankful for them 116 | memset ((void*)bufferPos, 0, 8); 117 | bufferPos += 8; 118 | 119 | // Copy across the message type 120 | *bufferPos = (uint8_t) msgType; 121 | bufferPos++; 122 | 123 | switch (msgType) 124 | { 125 | case BASE_MSG_INBOX_REQUEST: 126 | // Copy across inbox name 127 | msgInboxByteCount = strlen (replyInboxName) + 1; 128 | memcpy (bufferPos, replyInboxName, msgInboxByteCount); 129 | bufferPos += msgInboxByteCount; 130 | break; 131 | case BASE_MSG_INBOX_RESPONSE: 132 | msgTargetSubjectByteCount = strlen (targetSubject) + 1; 133 | memcpy (bufferPos, targetSubject, msgTargetSubjectByteCount); 134 | bufferPos += msgTargetSubjectByteCount; 135 | break; 136 | case BASE_MSG_SUB_REQUEST: 137 | case BASE_MSG_PUB_SUB: 138 | default: 139 | break; 140 | } 141 | 142 | // Copy across the payload 143 | memcpy ((void*)bufferPos, msgBuffer, msgSize); 144 | 145 | // Update payload length 146 | baseBridgeMamaMsgImpl_setPayloadSize(msg, msgSize); 147 | 148 | // Populate return pointers 149 | *target = serializedBuffer; 150 | *size = serializedSize; 151 | 152 | return status; 153 | } 154 | 155 | mama_status 156 | zmqBridgeMamaMsgImpl_deserialize (msgBridge msg, 157 | const void* source, 158 | mama_size_t size, 159 | mamaMsg target) 160 | { 161 | uint8_t* bufferPos = (uint8_t*)source; 162 | baseMsgType msgType = BASE_MSG_PUB_SUB; 163 | void* replyHandle = NULL; 164 | 165 | // Skip past the subject - don't care about that here 166 | bufferPos += strlen((char*)source) + 1; 167 | 168 | // Leave 8 bytes empty - receive side will be thankful for them 169 | memset ((void*)bufferPos, 0, 8); 170 | bufferPos += 8; 171 | 172 | // Set the message type 173 | msgType = (baseMsgType) *bufferPos; 174 | bufferPos++; 175 | 176 | switch (msgType) 177 | { 178 | case BASE_MSG_INBOX_REQUEST: 179 | baseBridgeMamaMsgImpl_getReplyHandle (msg, &replyHandle); 180 | 181 | baseBridgeMamaMsgReplyHandleImpl_setInboxName (&replyHandle, 182 | (const char*)bufferPos); 183 | bufferPos += strlen ((const char*)bufferPos) + 1; 184 | break; 185 | case BASE_MSG_INBOX_RESPONSE: 186 | baseBridgeMamaMsgImpl_setTargetSubject(msg, (const char*)bufferPos); 187 | bufferPos += strlen ((const char*)bufferPos) + 1; 188 | break; 189 | case BASE_MSG_SUB_REQUEST: 190 | case BASE_MSG_PUB_SUB: 191 | default: 192 | break; 193 | } 194 | 195 | // Parse the payload into a MAMA Message 196 | size_t payloadSize = size - (bufferPos - (uint8_t*)source); 197 | 198 | mama_log (MAMA_LOG_LEVEL_FINER, 199 | "zmqBridgeMamaMsgImpl_deserialize(): " 200 | "Received %lu bytes [payload=%lu; type=%d]", 201 | size, 202 | payloadSize, 203 | msgType); 204 | 205 | mama_status status = mamaMsgImpl_setMsgBuffer (target, 206 | (void*) bufferPos, 207 | (uint32_t)payloadSize, 208 | *bufferPos); 209 | 210 | return status; 211 | } 212 | -------------------------------------------------------------------------------- /src/subscription.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | /*========================================================================= 26 | = Includes = 27 | =========================================================================*/ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include "transport.h" 38 | #include "zmqdefs.h" 39 | #include "subscription.h" 40 | #include 41 | #include "zmqbridgefunctions.h" 42 | #include 43 | #include 44 | #include 45 | 46 | 47 | /*========================================================================= 48 | = Public interface implementation functions = 49 | =========================================================================*/ 50 | 51 | mama_status 52 | zmqBridgeMamaSubscription_create (subscriptionBridge* subscriber, 53 | const char* source, 54 | const char* symbol, 55 | mamaTransport tport, 56 | mamaQueue queue, 57 | mamaMsgCallbacks callback, 58 | mamaSubscription subscription, 59 | void* closure) 60 | { 61 | zmqSubscription* impl = NULL; 62 | zmqTransportBridge* transport = NULL; 63 | mama_status status = MAMA_STATUS_OK; 64 | 65 | if ( NULL == subscriber || NULL == subscription || NULL == tport ) 66 | { 67 | mama_log (MAMA_LOG_LEVEL_ERROR, 68 | "zmqBridgeMamaSubscription_create(): something NULL"); 69 | return MAMA_STATUS_NULL_ARG; 70 | } 71 | 72 | status = mamaTransport_getBridgeTransport (tport, 73 | (transportBridge*) &transport); 74 | 75 | if (MAMA_STATUS_OK != status || NULL == transport) 76 | { 77 | mama_log (MAMA_LOG_LEVEL_ERROR, 78 | "zmqBridgeMamaSubscription_create(): something NULL"); 79 | return MAMA_STATUS_NULL_ARG; 80 | } 81 | 82 | /* Allocate memory for zmq subscription implementation */ 83 | impl = (zmqSubscription*) calloc (1, sizeof (zmqSubscription)); 84 | if (NULL == impl) 85 | { 86 | return MAMA_STATUS_NOMEM; 87 | } 88 | 89 | mamaQueue_getNativeHandle(queue, &impl->mZmqQueue); 90 | impl->mMamaCallback = callback; 91 | impl->mMamaSubscription = subscription; 92 | impl->mMamaQueue = queue; 93 | impl->mTransport = transport; 94 | impl->mSymbol = symbol; 95 | impl->mClosure = closure; 96 | impl->mIsNotMuted = 1; 97 | impl->mIsTportDisconnected = 1; 98 | impl->mSubjectKey = NULL; 99 | 100 | /* Use a standard centralized method to determine a topic key */ 101 | zmqBridgeMamaSubscriptionImpl_generateSubjectKey (NULL, 102 | source, 103 | symbol, 104 | &impl->mSubjectKey); 105 | 106 | /* Register the endpoint */ 107 | endpointPool_registerWithoutIdentifier (transport->mSubEndpoints, 108 | impl->mSubjectKey, 109 | &impl->mEndpointIdentifier, 110 | impl); 111 | 112 | /* Set the message meta data to reflect a subscription request */ 113 | baseBridgeMamaMsgImpl_setMsgType (transport->mMsg, 114 | BASE_MSG_SUB_REQUEST); 115 | 116 | /* subscribe to the topic */ 117 | zmq_setsockopt (transport->mZmqSocketSubscriber, 118 | ZMQ_SUBSCRIBE, 119 | impl->mSubjectKey, 120 | strlen (impl->mSubjectKey)); 121 | 122 | mama_log (MAMA_LOG_LEVEL_FINEST, 123 | "zmqBridgeMamaSubscription_create(): " 124 | "created interest for %s.", 125 | impl->mSubjectKey); 126 | 127 | /* Mark this subscription as valid */ 128 | impl->mIsValid = 1; 129 | 130 | *subscriber = (subscriptionBridge) impl; 131 | 132 | return MAMA_STATUS_OK; 133 | } 134 | 135 | mama_status 136 | zmqBridgeMamaSubscription_mute (subscriptionBridge subscriber) 137 | { 138 | zmqSubscription* impl = (zmqSubscription*) subscriber; 139 | 140 | if (NULL == impl) 141 | { 142 | return MAMA_STATUS_NULL_ARG; 143 | } 144 | 145 | impl->mIsNotMuted = 0; 146 | 147 | return MAMA_STATUS_OK; 148 | } 149 | 150 | mama_status 151 | zmqBridgeMamaSubscription_destroy (subscriptionBridge subscriber) 152 | { 153 | zmqSubscription* impl = NULL; 154 | zmqTransportBridge* transportBridge = NULL; 155 | mamaSubscription parent = NULL; 156 | void* closure = NULL; 157 | wombat_subscriptionDestroyCB destroyCb = NULL; 158 | 159 | if (NULL == subscriber) 160 | { 161 | return MAMA_STATUS_NULL_ARG; 162 | } 163 | 164 | impl = (zmqSubscription*) subscriber; 165 | parent = impl->mMamaSubscription; 166 | closure = impl->mClosure; 167 | destroyCb = impl->mMamaCallback.onDestroy; 168 | transportBridge = impl->mTransport; 169 | 170 | /* Remove the subscription from the transport's subscription pool. */ 171 | if (NULL != transportBridge && NULL != transportBridge->mSubEndpoints 172 | && NULL != impl->mSubjectKey) 173 | { 174 | endpointPool_unregister (transportBridge->mSubEndpoints, 175 | impl->mSubjectKey, 176 | impl->mEndpointIdentifier); 177 | } 178 | 179 | if (NULL != impl->mSubjectKey) 180 | { 181 | free (impl->mSubjectKey); 182 | } 183 | 184 | if (NULL != impl->mEndpointIdentifier) 185 | { 186 | free ((void*)impl->mEndpointIdentifier); 187 | } 188 | 189 | free (impl); 190 | 191 | /* 192 | * Invoke the subscription callback to inform that the bridge has been 193 | * destroyed. 194 | */ 195 | if (NULL != destroyCb) 196 | (*(wombat_subscriptionDestroyCB)destroyCb)(parent, closure); 197 | 198 | return MAMA_STATUS_OK; 199 | } 200 | 201 | int 202 | zmqBridgeMamaSubscription_isValid (subscriptionBridge subscriber) 203 | { 204 | zmqSubscription* impl = (zmqSubscription*) subscriber; 205 | 206 | if (NULL != impl) 207 | { 208 | return impl->mIsValid; 209 | } 210 | return 0; 211 | } 212 | 213 | int 214 | zmqBridgeMamaSubscription_isTportDisconnected (subscriptionBridge subscriber) 215 | { 216 | zmqSubscription* impl = (zmqSubscription*) subscriber; 217 | if (NULL == impl) 218 | { 219 | return MAMA_STATUS_NULL_ARG; 220 | } 221 | return impl->mIsTportDisconnected; 222 | } 223 | 224 | mama_status 225 | zmqBridgeMamaSubscription_muteCurrentTopic (subscriptionBridge subscriber) 226 | { 227 | /* As there is one topic per subscription, this can act as an alias */ 228 | return zmqBridgeMamaSubscription_mute (subscriber); 229 | } 230 | 231 | 232 | /*========================================================================= 233 | = Public implementation functions = 234 | =========================================================================*/ 235 | 236 | /* 237 | * Internal function to ensure that the topic names are always calculated 238 | * in a particular way 239 | */ 240 | mama_status 241 | zmqBridgeMamaSubscriptionImpl_generateSubjectKey (const char* root, 242 | const char* source, 243 | const char* topic, 244 | char** keyTarget) 245 | { 246 | char subject[MAX_SUBJECT_LENGTH]; 247 | char* subjectPos = subject; 248 | size_t bytesRemaining = MAX_SUBJECT_LENGTH; 249 | size_t written = 0; 250 | 251 | if (NULL != root) 252 | { 253 | mama_log (MAMA_LOG_LEVEL_FINEST, 254 | "zmqBridgeMamaSubscriptionImpl_generateSubjectKey(): R."); 255 | written = snprintf (subjectPos, bytesRemaining, "%s", root); 256 | subjectPos += written; 257 | bytesRemaining -= written; 258 | } 259 | 260 | if (NULL != source) 261 | { 262 | mama_log (MAMA_LOG_LEVEL_FINEST, 263 | "zmqBridgeMamaSubscriptionImpl_generateSubjectKey(): S."); 264 | /* If these are not the first bytes, prepend with a period */ 265 | if(subjectPos != subject) 266 | { 267 | written = snprintf (subjectPos, bytesRemaining, ".%s", source); 268 | } 269 | else 270 | { 271 | written = snprintf (subjectPos, bytesRemaining, "%s", source); 272 | } 273 | subjectPos += written; 274 | bytesRemaining -= written; 275 | } 276 | 277 | if (NULL != topic) 278 | { 279 | mama_log (MAMA_LOG_LEVEL_FINEST, 280 | "zmqBridgeMamaSubscriptionImpl_generateSubjectKey(): T."); 281 | /* If these are not the first bytes, prepend with a period */ 282 | if (subjectPos != subject) 283 | { 284 | snprintf (subjectPos, bytesRemaining, ".%s", topic); 285 | } 286 | else 287 | { 288 | snprintf (subjectPos, bytesRemaining, "%s", topic); 289 | } 290 | } 291 | 292 | /* 293 | * Allocate the memory for copying the string. Caller is responsible for 294 | * destroying. 295 | */ 296 | *keyTarget = strdup (subject); 297 | if (NULL == *keyTarget) 298 | { 299 | return MAMA_STATUS_NOMEM; 300 | } 301 | else 302 | { 303 | return MAMA_STATUS_OK; 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /src/publisher.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | /*========================================================================= 26 | = Includes = 27 | =========================================================================*/ 28 | 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include "transport.h" 38 | #include "zmqdefs.h" 39 | #include "mama/integration/bridge/base.h" 40 | #include "subscription.h" 41 | #include "mama/integration/endpointpool.h" 42 | #include "zmqbridgefunctions.h" 43 | #include "msg.h" 44 | #include 45 | #include 46 | 47 | /*========================================================================= 48 | = Typedefs, structs, enums and globals = 49 | =========================================================================*/ 50 | 51 | typedef struct zmqPublisherBridge 52 | { 53 | zmqTransportBridge* mTransport; 54 | const char* mTopic; 55 | const char* mSource; 56 | const char* mRoot; 57 | const char* mSubject; 58 | msgBridge mMamaBridgeMsg; 59 | mamaPublisher mParent; 60 | mamaPublisherCallbacks mCallbacks; 61 | void* mCallbackClosure; 62 | } zmqPublisherBridge; 63 | 64 | /*========================================================================= 65 | = Private implementation prototypes = 66 | =========================================================================*/ 67 | 68 | /** 69 | * When a zmq publisher is created, it calls this function to generate a 70 | * standard subject key using zmqBridgeMamaSubscriptionImpl_generateSubjectKey 71 | * with different parameters depending on if it's a market data publisher, 72 | * basic publisher or a data dictionary publisher. 73 | * 74 | * @param msg The MAMA message to enqueue for sending. 75 | * @param url The URL to eneueue the message for sending to. 76 | * @param impl The related zmq publisher bridge. 77 | * 78 | * @return mama_status indicating whether the method succeeded or failed. 79 | */ 80 | static mama_status 81 | zmqBridgeMamaPublisherImpl_buildSendSubject (zmqPublisherBridge* impl); 82 | 83 | 84 | /*========================================================================= 85 | = Public interface implementation functions = 86 | =========================================================================*/ 87 | 88 | mama_status 89 | zmqBridgeMamaPublisher_createByIndex (publisherBridge* result, 90 | mamaTransport tport, 91 | int tportIndex, 92 | const char* topic, 93 | const char* source, 94 | const char* root, 95 | mamaPublisher parent) 96 | { 97 | zmqPublisherBridge* impl = NULL; 98 | zmqTransportBridge* transport = NULL; 99 | mama_status status = MAMA_STATUS_OK; 100 | 101 | if (NULL == result 102 | || NULL == tport 103 | || NULL == parent) 104 | { 105 | return MAMA_STATUS_NULL_ARG; 106 | } 107 | 108 | transport = zmqBridgeMamaTransportImpl_getTransportBridge (tport); 109 | if (NULL == transport) 110 | { 111 | mama_log (MAMA_LOG_LEVEL_SEVERE, 112 | "zmqBridgeMamaPublisher_createByIndex(): " 113 | "Could not find transport."); 114 | return MAMA_STATUS_NULL_ARG; 115 | } 116 | 117 | impl = (zmqPublisherBridge*) calloc (1, sizeof (zmqPublisherBridge)); 118 | if (NULL == impl) 119 | { 120 | mama_log (MAMA_LOG_LEVEL_ERROR, 121 | "zmqBridgeMamaPublisher_createByIndex(): " 122 | "Could not allocate mem publisher."); 123 | return MAMA_STATUS_NOMEM; 124 | } 125 | 126 | /* Initialize the publisher members */ 127 | impl->mTransport = transport; 128 | impl->mParent = parent; 129 | 130 | /* Create an underlying bridge message with no parent to be used in sends */ 131 | status = baseBridgeMamaMsgImpl_createMsgOnly (&impl->mMamaBridgeMsg); 132 | if (MAMA_STATUS_OK != status) 133 | { 134 | mama_log (MAMA_LOG_LEVEL_ERROR, 135 | "zmqBridgeMamaPublisher_createByIndex(): " 136 | "Could not create zmq bridge message for publisher: %s.", 137 | mamaStatus_stringForStatus (status)); 138 | free (impl); 139 | return MAMA_STATUS_NOMEM; 140 | } 141 | 142 | if (NULL != topic) 143 | { 144 | impl->mTopic = topic; 145 | } 146 | 147 | if (NULL != source) 148 | { 149 | impl->mSource = source; 150 | } 151 | 152 | if (NULL != root) 153 | { 154 | impl->mRoot = root; 155 | } 156 | 157 | /* Generate a topic name based on the publisher details */ 158 | status = zmqBridgeMamaPublisherImpl_buildSendSubject (impl); 159 | 160 | /* Populate the publisherBridge pointer with the publisher implementation */ 161 | *result = (publisherBridge) impl; 162 | 163 | return status; 164 | } 165 | 166 | mama_status 167 | zmqBridgeMamaPublisher_destroy (publisherBridge publisher) 168 | { 169 | zmqPublisherBridge* impl = (zmqPublisherBridge*) publisher; 170 | 171 | /* Take a copy of the callbacks - we'll need those */ 172 | mamaPublisherCallbacks callbacks; 173 | mamaPublisher parent = NULL; 174 | void* closure = NULL; 175 | 176 | if (NULL == impl) 177 | { 178 | return MAMA_STATUS_NULL_ARG; 179 | } 180 | 181 | /* Take a copy of the callbacks - we'll need those */ 182 | callbacks = impl->mCallbacks; 183 | parent = impl->mParent; 184 | closure = impl->mCallbackClosure; 185 | 186 | if (NULL != impl->mSubject) 187 | { 188 | free ((void*) impl->mSubject); 189 | } 190 | if (NULL != impl->mMamaBridgeMsg) 191 | { 192 | baseBridgeMamaMsg_destroy (impl->mMamaBridgeMsg, 0); 193 | } 194 | 195 | free (impl); 196 | 197 | if (NULL != callbacks.onDestroy) 198 | { 199 | (*callbacks.onDestroy)(parent, closure); 200 | } 201 | 202 | return MAMA_STATUS_OK; 203 | } 204 | 205 | mama_status 206 | zmqBridgeMamaPublisher_send (publisherBridge publisher, mamaMsg msg) 207 | { 208 | mama_status status = MAMA_STATUS_OK; 209 | zmqPublisherBridge* impl = (zmqPublisherBridge*) publisher; 210 | char* url = NULL; 211 | baseMsgType type = BASE_MSG_PUB_SUB; 212 | 213 | if (NULL == impl) 214 | { 215 | mama_log (MAMA_LOG_LEVEL_ERROR, 216 | "zmqBridgeMamaPublisher_send(): No publisher."); 217 | return MAMA_STATUS_NULL_ARG; 218 | } 219 | else if (NULL == msg) 220 | { 221 | return MAMA_STATUS_NULL_ARG; 222 | } 223 | 224 | /* Get the bridge message type if specified already by inbox handlers */ 225 | baseBridgeMamaMsgImpl_getMsgType (impl->mMamaBridgeMsg, &type); 226 | 227 | switch (type) 228 | { 229 | case BASE_MSG_INBOX_REQUEST: 230 | /* Use the publisher's default send subject */ 231 | baseBridgeMamaMsg_setSendSubject (impl->mMamaBridgeMsg, 232 | impl->mSubject, 233 | impl->mSource); 234 | break; 235 | case BASE_MSG_INBOX_RESPONSE: 236 | /* The url should already be set for inbox responses as the replyTo */ 237 | baseBridgeMamaMsgImpl_getDestination (impl->mMamaBridgeMsg, &url); 238 | break; 239 | default: 240 | /* Use the publisher's default send subject */ 241 | baseBridgeMamaMsg_setSendSubject (impl->mMamaBridgeMsg, 242 | impl->mSubject, 243 | impl->mSource); 244 | break; 245 | } 246 | 247 | void* buf = NULL; 248 | size_t bufSize = 0; 249 | size_t payloadSize = 0; 250 | /* Pack the provided MAMA message into a proton message */ 251 | zmqBridgeMamaMsgImpl_serialize (impl->mMamaBridgeMsg, msg, &buf, &bufSize); 252 | baseBridgeMamaMsgImpl_getPayloadSize (impl->mMamaBridgeMsg, &payloadSize); 253 | 254 | int i = zmq_send (impl->mTransport->mZmqSocketPublisher, buf, bufSize, 0); 255 | mama_log (MAMA_LOG_LEVEL_FINER, 256 | "zmqBridgeMamaPublisher_send(): " 257 | "Sending %lu bytes [payload=%lu; type=%d]", 258 | bufSize, 259 | payloadSize, 260 | type, 261 | i); 262 | 263 | /* Reset the message type for the next publish */ 264 | baseBridgeMamaMsgImpl_setMsgType (impl->mMamaBridgeMsg, BASE_MSG_PUB_SUB); 265 | 266 | return status; 267 | } 268 | 269 | /* Send reply to inbox. */ 270 | mama_status 271 | zmqBridgeMamaPublisher_sendReplyToInbox (publisherBridge publisher, 272 | void* request, 273 | mamaMsg reply) 274 | { 275 | zmqPublisherBridge* impl = (zmqPublisherBridge*) publisher; 276 | mamaMsg requestMsg = (mamaMsg) request; 277 | const char* inboxSubject = NULL; 278 | const char* replyTo = NULL; 279 | msgBridge bridgeMsg = NULL; 280 | mama_status status = MAMA_STATUS_OK; 281 | 282 | if (NULL == publisher || NULL == request || NULL == reply) 283 | { 284 | return MAMA_STATUS_NULL_ARG; 285 | } 286 | 287 | /* Set properties for the outgoing bridge message */ 288 | baseBridgeMamaMsgImpl_setMsgType (impl->mMamaBridgeMsg, 289 | BASE_MSG_INBOX_RESPONSE); 290 | 291 | /* Target is for MD subscriptions to respond to this particular topic */ 292 | baseBridgeMamaMsgImpl_setTargetSubject (impl->mMamaBridgeMsg, 293 | impl->mSubject); 294 | 295 | /* Get the incoming bridge message from the mamaMsg */ 296 | status = mamaMsgImpl_getBridgeMsg (requestMsg, &bridgeMsg); 297 | if (MAMA_STATUS_OK != status) 298 | { 299 | mama_log (MAMA_LOG_LEVEL_ERROR, 300 | "zmqBridgeMamaPublisher_sendReplyToInbox(): " 301 | "Could not get bridge message from cached" 302 | " queue mamaMsg [%s]", 303 | mamaStatus_stringForStatus (status)); 304 | return status; 305 | } 306 | 307 | /* Get properties from the incoming bridge message */ 308 | status = baseBridgeMamaMsgImpl_getInboxName (bridgeMsg, 309 | (char**) &inboxSubject); 310 | if (MAMA_STATUS_OK != status) 311 | { 312 | mama_log (MAMA_LOG_LEVEL_ERROR, 313 | "zmqBridgeMamaPublisher_sendReplyToInbox(): " 314 | "Could not get inbox name [%s]", 315 | mamaStatus_stringForStatus (status)); 316 | return status; 317 | } 318 | 319 | status = baseBridgeMamaMsgImpl_getReplyTo (bridgeMsg, (char**) &replyTo); 320 | if (MAMA_STATUS_OK != status) 321 | { 322 | mama_log (MAMA_LOG_LEVEL_ERROR, 323 | "zmqBridgeMamaPublisher_sendReplyToInbox(): " 324 | "Could not get reply to [%s]", 325 | mamaStatus_stringForStatus (status)); 326 | return status; 327 | } 328 | 329 | if (NULL == inboxSubject) 330 | { 331 | mama_log (MAMA_LOG_LEVEL_ERROR, 332 | "zmqBridgeMamaPublisher_sendReplyToInbox(): " 333 | "No reply address specified - cannot respond to inbox %s.", 334 | inboxSubject); 335 | return status; 336 | } 337 | 338 | /* Set the send subject to publish onto the inbox subject */ 339 | status = baseBridgeMamaMsg_setSendSubject (impl->mMamaBridgeMsg, 340 | inboxSubject, 341 | impl->mSource); 342 | if (MAMA_STATUS_OK != status) 343 | { 344 | mama_log (MAMA_LOG_LEVEL_ERROR, 345 | "zmqBridgeMamaPublisher_sendReplyToInbox(): " 346 | "Could not set send subject '%s' [%s]", 347 | inboxSubject, 348 | mamaStatus_stringForStatus (status)); 349 | return status; 350 | } 351 | 352 | /* Set the destination to the replyTo URL */ 353 | status = baseBridgeMamaMsgImpl_setDestination (impl->mMamaBridgeMsg, 354 | replyTo); 355 | if (MAMA_STATUS_OK != status) 356 | { 357 | mama_log (MAMA_LOG_LEVEL_ERROR, 358 | "zmqBridgeMamaPublisher_sendReplyToInbox(): " 359 | "Could not set destination '%s' [%s]", 360 | replyTo, 361 | mamaStatus_stringForStatus (status)); 362 | return status; 363 | } 364 | 365 | /* Fire out the message to the inbox */ 366 | return zmqBridgeMamaPublisher_send (publisher, reply); 367 | } 368 | 369 | mama_status 370 | zmqBridgeMamaPublisher_sendReplyToInboxHandle (publisherBridge publisher, 371 | void* inbox, 372 | mamaMsg reply) 373 | { 374 | zmqPublisherBridge* impl = (zmqPublisherBridge*) publisher; 375 | const char* inboxSubject = NULL; 376 | const char* replyTo = NULL; 377 | mama_status status = MAMA_STATUS_OK; 378 | 379 | if (NULL == publisher || NULL == inbox || NULL == reply) 380 | { 381 | return MAMA_STATUS_NULL_ARG; 382 | } 383 | 384 | /* Set properties for the outgoing bridge message */ 385 | baseBridgeMamaMsgImpl_setMsgType (impl->mMamaBridgeMsg, 386 | BASE_MSG_INBOX_RESPONSE); 387 | 388 | /* Target is for MD subscriptions to respond to this particular topic */ 389 | baseBridgeMamaMsgImpl_setTargetSubject (impl->mMamaBridgeMsg, 390 | impl->mSubject); 391 | 392 | /* Get properties from the incoming bridge message */ 393 | status = baseBridgeMamaMsgReplyHandleImpl_getInboxName ( 394 | inbox, 395 | (char**) &inboxSubject); 396 | if (MAMA_STATUS_OK != status) 397 | { 398 | mama_log (MAMA_LOG_LEVEL_ERROR, 399 | "zmqBridgeMamaPublisher_sendReplyToInbox(): " 400 | "Could not get inbox name [%s]", 401 | mamaStatus_stringForStatus (status)); 402 | return status; 403 | } 404 | 405 | status = baseBridgeMamaMsgReplyHandleImpl_getReplyTo ( 406 | inbox, 407 | (char**) &replyTo); 408 | if (MAMA_STATUS_OK != status) 409 | { 410 | mama_log (MAMA_LOG_LEVEL_ERROR, 411 | "zmqBridgeMamaPublisher_sendReplyToInbox(): " 412 | "Could not get reply to [%s]", 413 | mamaStatus_stringForStatus (status)); 414 | return status; 415 | } 416 | 417 | 418 | if (NULL == inboxSubject || NULL == replyTo) 419 | { 420 | mama_log (MAMA_LOG_LEVEL_ERROR, 421 | "zmqBridgeMamaPublisher_sendReplyToInboxHandle(): " 422 | "No reply address specified - cannot respond to inbox %s.", 423 | inboxSubject); 424 | return status; 425 | } 426 | 427 | /* Set the send subject to publish onto the inbox subject */ 428 | status = baseBridgeMamaMsg_setSendSubject (impl->mMamaBridgeMsg, 429 | inboxSubject, 430 | impl->mSource); 431 | if (MAMA_STATUS_OK != status) 432 | { 433 | mama_log (MAMA_LOG_LEVEL_ERROR, 434 | "zmqBridgeMamaPublisher_sendReplyToInboxHandle(): " 435 | "Could not set send subject '%s' [%s]", 436 | inboxSubject, 437 | mamaStatus_stringForStatus (status)); 438 | return status; 439 | } 440 | 441 | /* Set the destination to the replyTo URL */ 442 | status = baseBridgeMamaMsgImpl_setDestination (impl->mMamaBridgeMsg, 443 | replyTo); 444 | if (MAMA_STATUS_OK != status) 445 | { 446 | mama_log (MAMA_LOG_LEVEL_ERROR, 447 | "zmqBridgeMamaPublisher_sendReplyToInboxHandle(): " 448 | "Could not set destination '%s' [%s]", 449 | replyTo, 450 | mamaStatus_stringForStatus (status)); 451 | return status; 452 | } 453 | 454 | /* Fire out the message to the inbox */ 455 | return zmqBridgeMamaPublisher_send (publisher, reply); 456 | } 457 | 458 | mama_status 459 | zmqBridgeMamaPublisher_sendFromInbox (publisherBridge publisher, 460 | mamaInbox inbox, 461 | mamaMsg msg) 462 | { 463 | return zmqBridgeMamaPublisher_sendFromInboxByIndex (publisher, 464 | 0, 465 | inbox, 466 | msg); 467 | } 468 | 469 | /* Send a message from the specified inbox using the throttle. */ 470 | mama_status 471 | zmqBridgeMamaPublisher_sendFromInboxByIndex (publisherBridge publisher, 472 | int tportIndex, 473 | mamaInbox inbox, 474 | mamaMsg msg) 475 | { 476 | zmqPublisherBridge* impl = (zmqPublisherBridge*) publisher; 477 | const char* replyAddr = NULL; 478 | inboxBridge inboxImpl = NULL; 479 | mama_status status = MAMA_STATUS_OK; 480 | 481 | if (NULL == impl || NULL == inbox || NULL == msg) 482 | { 483 | return MAMA_STATUS_NULL_ARG; 484 | } 485 | 486 | /* Get the inbox which you want the publisher to respond to */ 487 | inboxImpl = mamaInboxImpl_getInboxBridge (inbox); 488 | replyAddr = baseBridgeMamaInboxImpl_getReplySubject (inboxImpl); 489 | 490 | /* Mark this as being a request from an inbox */ 491 | status = baseBridgeMamaMsgImpl_setMsgType (impl->mMamaBridgeMsg, 492 | BASE_MSG_INBOX_REQUEST); 493 | if (MAMA_STATUS_OK != status) 494 | { 495 | mama_log (MAMA_LOG_LEVEL_ERROR, 496 | "zmqBridgeMamaPublisher_sendFromInboxByIndex(): " 497 | "Failed to set message type [%s]", 498 | mamaStatus_stringForStatus (status)); 499 | return status; 500 | } 501 | 502 | /* Update meta data in outgoing message to reflect the inbox name */ 503 | status = baseBridgeMamaMsgImpl_setInboxName (impl->mMamaBridgeMsg, 504 | replyAddr); 505 | if (MAMA_STATUS_OK != status) 506 | { 507 | mama_log (MAMA_LOG_LEVEL_ERROR, 508 | "zmqBridgeMamaPublisher_sendFromInboxByIndex(): " 509 | "Failed to set inbox name [%s]", 510 | mamaStatus_stringForStatus (status)); 511 | return status; 512 | } 513 | 514 | return zmqBridgeMamaPublisher_send (publisher, msg);; 515 | } 516 | 517 | mama_status 518 | zmqBridgeMamaPublisher_setUserCallbacks (publisherBridge publisher, 519 | mamaQueue queue, 520 | mamaPublisherCallbacks* cb, 521 | void* closure) 522 | { 523 | zmqPublisherBridge* impl = (zmqPublisherBridge*) publisher; 524 | 525 | if (NULL == impl || NULL == cb) 526 | { 527 | return MAMA_STATUS_NULL_ARG; 528 | } 529 | /* Take a copy of the callbacks */ 530 | impl->mCallbacks = *cb; 531 | impl->mCallbackClosure = closure; 532 | 533 | return MAMA_STATUS_OK; 534 | } 535 | 536 | /*========================================================================= 537 | = Private implementation functions = 538 | =========================================================================*/ 539 | 540 | mama_status 541 | zmqBridgeMamaPublisherImpl_buildSendSubject (zmqPublisherBridge* impl) 542 | { 543 | char* keyTarget = NULL; 544 | 545 | /* If this is a special _MD publisher, lose the topic unless dictionary */ 546 | if (impl->mRoot != NULL) 547 | { 548 | /* 549 | * May use strlen here to increase speed but would need to test to 550 | * verify this is the only circumstance in which we want to consider the 551 | * topic when a root is specified. 552 | */ 553 | if (strcmp (impl->mRoot, "_MDDD") == 0) 554 | { 555 | zmqBridgeMamaSubscriptionImpl_generateSubjectKey (impl->mRoot, 556 | impl->mSource, 557 | impl->mTopic, 558 | &keyTarget); 559 | } 560 | else 561 | { 562 | zmqBridgeMamaSubscriptionImpl_generateSubjectKey (impl->mRoot, 563 | impl->mSource, 564 | NULL, 565 | &keyTarget); 566 | } 567 | } 568 | /* If this isn't a special _MD publisher */ 569 | else 570 | { 571 | zmqBridgeMamaSubscriptionImpl_generateSubjectKey (NULL, 572 | impl->mSource, 573 | impl->mTopic, 574 | &keyTarget); 575 | } 576 | 577 | /* Set the subject for publishing here */ 578 | impl->mSubject = keyTarget; 579 | 580 | return MAMA_STATUS_OK; 581 | } 582 | -------------------------------------------------------------------------------- /src/transport.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Frank Quinn (http://fquinner.github.io) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | /*========================================================================= 26 | = Includes = 27 | =========================================================================*/ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include "transport.h" 41 | #include "zmqdefs.h" 42 | #include "msg.h" 43 | #include 44 | #include 45 | #include "zmqbridgefunctions.h" 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | 52 | /*========================================================================= 53 | = Macros = 54 | =========================================================================*/ 55 | 56 | /* Transport configuration parameters */ 57 | #define TPORT_PARAM_PREFIX "mama.zmq.transport" 58 | #define TPORT_PARAM_OUTGOING_URL "outgoing_url" 59 | #define TPORT_PARAM_INCOMING_URL "incoming_url" 60 | #define TPORT_PARAM_MSG_POOL_SIZE "msg_pool_size" 61 | #define TPORT_PARAM_MSG_NODE_SIZE "msg_node_size" 62 | #define TPORT_PARAM_ZMQ_SNDHWM "zmq_sndhwm" 63 | #define TPORT_PARAM_ZMQ_RCVHWM "zmq_rcvhwm" 64 | #define TPORT_PARAM_ZMQ_AFFINITY "zmq_affinity" 65 | #define TPORT_PARAM_ZMQ_IDENTITY "zmq_identity" 66 | #define TPORT_PARAM_ZMQ_SNDBUF "zmq_sndbuf" 67 | #define TPORT_PARAM_ZMQ_RCVBUF "zmq_rcvbuf" 68 | #define TPORT_PARAM_ZMQ_RECONNECT_IVL "zmq_reconnect_ivl" 69 | #define TPORT_PARAM_ZMQ_RECONNECT_IVL_MAX "zmq_reconnect_ivl_max" 70 | #define TPORT_PARAM_ZMQ_BACKLOG "zmq_backlog" 71 | #define TPORT_PARAM_ZMQ_MAXMSGSIZE "zmq_maxmsgsize" 72 | #define TPORT_PARAM_ZMQ_RCVTIMEO "zmq_rcvtimeo" 73 | #define TPORT_PARAM_ZMQ_SNDTIMEO "zmq_sndtimeo" 74 | #define TPORT_PARAM_ZMQ_RATE "zmq_rate" 75 | 76 | /* Default values for corresponding configuration parameters */ 77 | #define DEFAULT_SUB_OUTGOING_URL "tcp://*:5557" 78 | #define DEFAULT_SUB_INCOMING_URL "tcp://127.0.0.1:5556" 79 | #define DEFAULT_PUB_OUTGOING_URL "tcp://*:5556" 80 | #define DEFAULT_PUB_INCOMING_URL "tcp://127.0.0.1:5557" 81 | #define DEFAULT_MEMPOOL_SIZE "1024" 82 | #define DEFAULT_MEMNODE_SIZE "4096" 83 | #define DEFAULT_ZMQ_SNDHWM "0" /* ZMQ Default = 1000 */ 84 | #define DEFAULT_ZMQ_RCVHWM "0" /* ZMQ Default = 1000 */ 85 | #define DEFAULT_ZMQ_AFFINITY "0" /* ZMQ Default */ 86 | #define DEFAULT_ZMQ_IDENTITY NULL /* ZMQ Default */ 87 | #define DEFAULT_ZMQ_SNDBUF "0" /* ZMQ Default */ 88 | #define DEFAULT_ZMQ_RCVBUF "0" /* ZMQ Default */ 89 | #define DEFAULT_ZMQ_RECONNECT_IVL "100" /* ZMQ Default */ 90 | #define DEFAULT_ZMQ_RECONNECT_IVL_MAX "0" /* ZMQ Default */ 91 | #define DEFAULT_ZMQ_BACKLOG "100" /* ZMQ Default */ 92 | #define DEFAULT_ZMQ_MAXMSGSIZE "-1" /* ZMQ Default */ 93 | #define DEFAULT_ZMQ_RCVTIMEO "10" /* ZMQ Default = -1 */ 94 | #define DEFAULT_ZMQ_SNDTIMEO "-1" /* ZMQ Default */ 95 | #define DEFAULT_ZMQ_RATE "1000000" /* ZMQ Default = 100 */ 96 | 97 | /* Non configurable runtime defaults */ 98 | #define PARAM_NAME_MAX_LENGTH 1024L 99 | 100 | #define ZMQ_SET_SOCKET_OPTIONS(type,impl,opt,map) \ 101 | do \ 102 | { \ 103 | const char* valStr = zmqBridgeMamaTransportImpl_getParameter ( \ 104 | DEFAULT_ZMQ_ ## opt, \ 105 | "%s.%s.%s", \ 106 | TPORT_PARAM_PREFIX, \ 107 | impl->mName, \ 108 | TPORT_PARAM_ZMQ_ ## opt); \ 109 | type value = (type) map (valStr); \ 110 | \ 111 | mama_log (MAMA_LOG_LEVEL_FINE, \ 112 | "zmqBridgeMamaTransportImpl_setSocketOptionInt(): Setting " \ 113 | "ZeroMQ socket option %s=%s for transport %s", \ 114 | TPORT_PARAM_ZMQ_ ## opt, \ 115 | valStr, \ 116 | impl->mName); \ 117 | \ 118 | zmq_setsockopt (impl->mZmqSocketPublisher, ZMQ_ ## opt, &value, sizeof(int)); \ 119 | zmq_setsockopt (impl->mZmqSocketSubscriber, ZMQ_ ## opt, &value, sizeof(int)); \ 120 | } while (0); 121 | 122 | /*========================================================================= 123 | = Private implementation prototypes = 124 | =========================================================================*/ 125 | 126 | /** 127 | * This function is called in the create function and is responsible for 128 | * actually subscribing to any transport level data sources and forking off the 129 | * recv dispatch thread for proton. 130 | * 131 | * @param impl Qpid transport bridge to start 132 | * 133 | * @return mama_status indicating whether the method succeeded or failed. 134 | */ 135 | static mama_status 136 | zmqBridgeMamaTransportImpl_start (zmqTransportBridge* impl); 137 | 138 | /** 139 | * This function is called in the destroy function and is responsible for 140 | * stopping the proton messengers and joining back with the recv thread created 141 | * in zmqBridgeMamaTransportImpl_start. 142 | * 143 | * @param impl Qpid transport bridge to start 144 | * 145 | * @return mama_status indicating whether the method succeeded or failed. 146 | */ 147 | static mama_status 148 | zmqBridgeMamaTransportImpl_stop (zmqTransportBridge* impl); 149 | 150 | /** 151 | * This function is a queue callback which is enqueued in the recv thread and 152 | * is then fired once it has reached the head of the queue. 153 | * 154 | * @param queue MAMA queue from which this callback was fired 155 | * @param closure In this instance, the closure is the zmqMsgNode which was 156 | * pulled from the pool in the recv callback and then sent 157 | * down the MAMA queue. 158 | * 159 | * @return mama_status indicating whether the method succeeded or failed. 160 | */ 161 | static void MAMACALLTYPE 162 | zmqBridgeMamaTransportImpl_queueCallback (mamaQueue queue, void* closure); 163 | 164 | /** 165 | * This is a local function for parsing long configuration parameters from the 166 | * MAMA properties object, and supports minimum and maximum limits as well 167 | * as default values to reduce the amount of code duplicated throughout. 168 | * 169 | * @param defaultVal This is the default value to use if the parameter does not 170 | * exist in the configuration file 171 | * @param minimum If the parameter obtained from the configuration file is 172 | * less than this value, this value will be used. 173 | * @param maximum If the parameter obtained from the configuration file is 174 | * greater than this value, this value will be used. 175 | * @param format This is the format string which is used to build the 176 | * name of the configuration parameter which is to be parsed. 177 | * @param ... This is the variable list of arguments to be used along 178 | * with the format string. 179 | * 180 | * @return long int containing the paramter value, default, minimum or maximum. 181 | */ 182 | /* 183 | static long int 184 | zmqBridgeMamaTransportImpl_getParameterAsLong (long defaultVal, 185 | long minimum, 186 | long maximum, 187 | const char* format, 188 | ...); 189 | */ 190 | /** 191 | * This is a local function for parsing string configuration parameters from the 192 | * MAMA properties object, and supports default values. This function should 193 | * be used where the configuration parameter itself can be variable. 194 | * 195 | * @param defaultVal This is the default value to use if the parameter does not 196 | * exist in the configuration file 197 | * @param paramName The format and variable list combine to form the real 198 | * configuration parameter used. This configuration parameter 199 | * will be stored at this location so the calling function 200 | * can log this. 201 | * @param format This is the format string which is used to build the 202 | * name of the configuration parameter which is to be parsed. 203 | * @param ... This is the variable list of arguments to be used along 204 | * with the format string. 205 | * 206 | * @return const char* containing the parameter value or the default. 207 | */ 208 | static const char* 209 | zmqBridgeMamaTransportImpl_getParameterWithVaList (char* defaultVal, 210 | char* paramName, 211 | const char* format, 212 | va_list arguments); 213 | 214 | /** 215 | * This is a local function for parsing string configuration parameters from the 216 | * MAMA properties object, and supports default values. This function should 217 | * be used where the configuration parameter itself can be variable. 218 | * 219 | * @param defaultVal This is the default value to use if the parameter does not 220 | * exist in the configuration file 221 | * @param format This is the format string which is used to build the 222 | * name of the configuration parameter which is to be parsed. 223 | * @param ... This is the variable list of arguments to be used along 224 | * with the format string. 225 | * 226 | * @return const char* containing the parameter value or the default. 227 | */ 228 | static const char* 229 | zmqBridgeMamaTransportImpl_getParameter (const char* defaultVal, 230 | const char* format, 231 | ...); 232 | 233 | /** 234 | * This function is called on its own thread to run the main recv dispatch 235 | * for all messages coming off the mIncoming messenger. This function is 236 | * responsible for routing all incoming messages to their required destination 237 | * and parsing all administrative messages. 238 | * 239 | * @param closure In this case, the closure refers to the zmqTransportBridge 240 | */ 241 | static void* 242 | zmqBridgeMamaTransportImpl_dispatchThread (void* closure); 243 | 244 | void MAMACALLTYPE 245 | zmqBridgeMamaTransportImpl_queueClosureCleanupCb (void* closure); 246 | 247 | /*========================================================================= 248 | = Public interface implementation functions = 249 | =========================================================================*/ 250 | 251 | int 252 | zmqBridgeMamaTransport_isValid (transportBridge transport) 253 | { 254 | zmqTransportBridge* impl = (zmqTransportBridge*) transport; 255 | int status = 0; 256 | 257 | if (NULL != impl) 258 | { 259 | status = impl->mIsValid; 260 | } 261 | return status; 262 | } 263 | 264 | mama_status 265 | zmqBridgeMamaTransport_destroy (transportBridge transport) 266 | { 267 | zmqTransportBridge* impl = NULL; 268 | mama_status status = MAMA_STATUS_OK; 269 | 270 | if (NULL == transport) 271 | { 272 | return MAMA_STATUS_NULL_ARG; 273 | } 274 | 275 | impl = (zmqTransportBridge*) transport; 276 | 277 | status = zmqBridgeMamaTransportImpl_stop (impl); 278 | 279 | zmq_close (impl->mZmqSocketDispatcher); 280 | zmq_close (impl->mZmqSocketPublisher); 281 | zmq_close (impl->mZmqSocketSubscriber); 282 | 283 | zmq_ctx_destroy(impl->mZmqContext); 284 | 285 | 286 | endpointPool_destroy (impl->mSubEndpoints); 287 | endpointPool_destroy (impl->mPubEndpoints); 288 | 289 | free (impl); 290 | 291 | return status; 292 | } 293 | 294 | mama_status 295 | zmqBridgeMamaTransport_create (transportBridge* result, 296 | const char* name, 297 | mamaTransport parent) 298 | { 299 | zmqTransportBridge* impl = NULL; 300 | mama_status status = MAMA_STATUS_OK; 301 | char* mDefIncoming = NULL; 302 | char* mDefOutgoing = NULL; 303 | const char* uri = NULL; 304 | int uri_index = 0; 305 | 306 | if (NULL == result || NULL == name || NULL == parent) 307 | { 308 | return MAMA_STATUS_NULL_ARG; 309 | } 310 | 311 | impl = (zmqTransportBridge*) calloc (1, sizeof (zmqTransportBridge)); 312 | 313 | /* Back reference the MAMA transport */ 314 | impl->mTransport = parent; 315 | 316 | /* Initialize the dispatch thread pointer */ 317 | impl->mOmzmqDispatchThread = 0; 318 | impl->mOmzmqDispatchStatus = MAMA_STATUS_OK; 319 | impl->mName = name; 320 | 321 | mama_log (MAMA_LOG_LEVEL_FINE, 322 | "zmqBridgeMamaTransport_create(): Initializing Transportttt %s", 323 | name); 324 | 325 | impl->mMemoryPoolSize = atol(zmqBridgeMamaTransportImpl_getParameter ( 326 | DEFAULT_MEMPOOL_SIZE, 327 | "%s.%s.%s", 328 | TPORT_PARAM_PREFIX, 329 | name, 330 | TPORT_PARAM_MSG_POOL_SIZE)); 331 | mama_log(MAMA_LOG_LEVEL_FINE, 332 | "zmqBridgeMamaTransport_create():creating endpoint A %s", 333 | name); 334 | impl->mMemoryNodeSize = atol(zmqBridgeMamaTransportImpl_getParameter ( 335 | DEFAULT_MEMNODE_SIZE, 336 | "%s.%s.%s", 337 | TPORT_PARAM_PREFIX, 338 | name, 339 | TPORT_PARAM_MSG_NODE_SIZE)); 340 | 341 | mama_log (MAMA_LOG_LEVEL_FINE, 342 | "zmqBridgeMamaTransport_create(): Any message pools created will " 343 | "contain %lu nodes of %lu bytes.", 344 | name, 345 | impl->mMemoryPoolSize, 346 | impl->mMemoryNodeSize); 347 | 348 | if (0 == strcmp(impl->mName, "pub")) 349 | { 350 | mDefIncoming = DEFAULT_PUB_INCOMING_URL; 351 | mDefOutgoing = DEFAULT_PUB_OUTGOING_URL; 352 | } 353 | else 354 | { 355 | mDefIncoming = DEFAULT_SUB_INCOMING_URL; 356 | mDefOutgoing = DEFAULT_SUB_OUTGOING_URL; 357 | } 358 | 359 | /* Start with bare incoming address */ 360 | impl->mIncomingAddress[0] = zmqBridgeMamaTransportImpl_getParameter ( 361 | mDefIncoming, 362 | "%s.%s.%s", 363 | TPORT_PARAM_PREFIX, 364 | name, 365 | TPORT_PARAM_INCOMING_URL); 366 | 367 | /* Now parse any _0, _1 etc. */ 368 | uri_index = 0; 369 | while (NULL != (uri = zmqBridgeMamaTransportImpl_getParameter ( 370 | NULL, 371 | "%s.%s.%s_%d", 372 | TPORT_PARAM_PREFIX, 373 | name, 374 | TPORT_PARAM_INCOMING_URL, 375 | uri_index))) 376 | { 377 | impl->mIncomingAddress[uri_index] = uri; 378 | uri_index++; 379 | } 380 | 381 | /* Start with bare outgoing address */ 382 | impl->mOutgoingAddress[0] = zmqBridgeMamaTransportImpl_getParameter ( 383 | mDefOutgoing, 384 | "%s.%s.%s", 385 | TPORT_PARAM_PREFIX, 386 | name, 387 | TPORT_PARAM_OUTGOING_URL); 388 | 389 | /* Now parse any _0, _1 etc. */ 390 | uri_index = 0; 391 | while (NULL != (uri = zmqBridgeMamaTransportImpl_getParameter ( 392 | NULL, 393 | "%s.%s.%s_%d", 394 | TPORT_PARAM_PREFIX, 395 | name, 396 | TPORT_PARAM_OUTGOING_URL, 397 | uri_index))) 398 | { 399 | impl->mOutgoingAddress[uri_index] = uri; 400 | uri_index++; 401 | } 402 | mama_log(MAMA_LOG_LEVEL_FINE, 403 | "zmqBridgeMamaTransport_create():creating endpoint 1 %s", 404 | name); 405 | status = endpointPool_create (&impl->mSubEndpoints, "mSubEndpoints"); 406 | if (MAMA_STATUS_OK != status) 407 | { 408 | mama_log (MAMA_LOG_LEVEL_ERROR, 409 | "zmqBridgeMamaTransport_create(): " 410 | "Failed to create subscribing endpoints"); 411 | free (impl); 412 | return MAMA_STATUS_PLATFORM; 413 | } 414 | mama_log(MAMA_LOG_LEVEL_FINE, 415 | "zmqBridgeMamaTransport_create(): Creating endpoint 2 %s", 416 | name); 417 | status = endpointPool_create (&impl->mPubEndpoints, "mPubEndpoints"); 418 | if (MAMA_STATUS_OK != status) 419 | { 420 | mama_log (MAMA_LOG_LEVEL_ERROR, 421 | "zmqBridgeMamaTransport_create(): " 422 | "Failed to create publishing endpoints"); 423 | free (impl); 424 | return MAMA_STATUS_PLATFORM; 425 | } 426 | 427 | impl->mIsValid = 1; 428 | 429 | *result = (transportBridge) impl; 430 | 431 | return zmqBridgeMamaTransportImpl_start (impl); 432 | } 433 | 434 | 435 | /*========================================================================= 436 | = Public implementation functions = 437 | =========================================================================*/ 438 | 439 | zmqTransportBridge* 440 | zmqBridgeMamaTransportImpl_getTransportBridge (mamaTransport transport) 441 | { 442 | zmqTransportBridge* impl; 443 | mama_status status = MAMA_STATUS_OK; 444 | 445 | status = mamaTransport_getBridgeTransport (transport, 446 | (transportBridge*) &impl); 447 | 448 | if (status != MAMA_STATUS_OK || impl == NULL) 449 | { 450 | return NULL; 451 | } 452 | 453 | return impl; 454 | } 455 | 456 | 457 | /*========================================================================= 458 | = Private implementation functions = 459 | =========================================================================*/ 460 | int 461 | zmqBridgeMamaTransportImpl_setupSocket (void* socket, const char* uri, zmqTransportDirection direction) 462 | { 463 | int rc = 0; 464 | char tportTypeStr[16]; 465 | char* firstColon = NULL; 466 | zmqTransportType tportType = ZMQ_TPORT_TYPE_UNKNOWN; 467 | /* If set to non zero, will bind rather than connect */ 468 | int isBinding = 0; 469 | 470 | strncpy (tportTypeStr, uri, sizeof(tportTypeStr)); 471 | tportTypeStr[sizeof(tportTypeStr)-1] = '\0'; 472 | firstColon = strchr(tportTypeStr, ':'); 473 | if (NULL != firstColon) 474 | { 475 | *firstColon = '\0'; 476 | } 477 | 478 | if (0 == strcmp(tportTypeStr, "tcp")) 479 | { 480 | tportType = ZMQ_TPORT_TYPE_TCP; 481 | } 482 | else if (0 == strcmp(tportTypeStr, "epgm")) 483 | { 484 | tportType = ZMQ_TPORT_TYPE_EPGM; 485 | } 486 | else if (0 == strcmp(tportTypeStr, "pgm")) 487 | { 488 | tportType = ZMQ_TPORT_TYPE_PGM; 489 | } 490 | else if (0 == strcmp(tportTypeStr, "ipc")) 491 | { 492 | tportType = ZMQ_TPORT_TYPE_IPC; 493 | } 494 | else 495 | { 496 | mama_log (MAMA_LOG_LEVEL_ERROR, 497 | "Unknown ZeroMQ transport type found: %s. Trying anyway.", 498 | tportTypeStr); 499 | } 500 | 501 | mama_log (MAMA_LOG_LEVEL_FINE, "Found ZeroMQ transport type %s (%d)", 502 | tportTypeStr, tportType); 503 | 504 | /* Get the transport type from the uri */ 505 | switch (direction) 506 | { 507 | case ZMQ_TPORT_DIRECTION_INCOMING: 508 | switch (tportType) 509 | { 510 | case ZMQ_TPORT_TYPE_TCP: 511 | if (strchr(uri, '*')) 512 | { 513 | isBinding = 1; 514 | } 515 | break; 516 | case ZMQ_TPORT_TYPE_EPGM: 517 | case ZMQ_TPORT_TYPE_PGM: 518 | case ZMQ_TPORT_TYPE_IPC: 519 | default: 520 | break; 521 | } 522 | break; 523 | case ZMQ_TPORT_DIRECTION_OUTGOING: 524 | switch (tportType) 525 | { 526 | case ZMQ_TPORT_TYPE_TCP: 527 | if (strchr(uri, '*')) 528 | { 529 | isBinding = 1; 530 | } 531 | break; 532 | case ZMQ_TPORT_TYPE_IPC: 533 | isBinding = 1; 534 | break; 535 | case ZMQ_TPORT_TYPE_EPGM: 536 | case ZMQ_TPORT_TYPE_PGM: 537 | default: 538 | break; 539 | } 540 | break; 541 | default: 542 | mama_log (MAMA_LOG_LEVEL_ERROR, "zmqBridgeMamaTransportImpl_setupSocket(): " 543 | "Didn't recognize transport direction %d", 544 | direction); 545 | break; 546 | } 547 | 548 | /* If this is a binding transport */ 549 | if (isBinding) 550 | { 551 | rc = zmq_bind (socket, uri); 552 | if (0 != rc) 553 | { 554 | mama_log (MAMA_LOG_LEVEL_ERROR, "zmqBridgeMamaTransportImpl_setupSocket(): " 555 | "zmq_bind returned %d trying to bind to '%s' (%s)", 556 | rc, 557 | uri, 558 | strerror(errno)); 559 | } 560 | } 561 | else 562 | { 563 | rc = zmq_connect (socket, uri); 564 | if (0 != rc) 565 | { 566 | mama_log (MAMA_LOG_LEVEL_ERROR, "zmqBridgeMamaTransportImpl_start(): " 567 | "zmq_connect returned %d trying to connect to '%s' (%s)", 568 | rc, 569 | uri, 570 | strerror(errno)); 571 | } 572 | } 573 | return rc; 574 | } 575 | 576 | mama_status 577 | zmqBridgeMamaTransportImpl_start (zmqTransportBridge* impl) 578 | { 579 | int rc = 0; 580 | int i = 0; 581 | 582 | if (NULL == impl) 583 | { 584 | mama_log (MAMA_LOG_LEVEL_ERROR, 585 | "zmqBridgeMamaTransportImpl_start(): transport NULL"); 586 | return MAMA_STATUS_NULL_ARG; 587 | } 588 | 589 | 590 | impl->mZmqContext = zmq_ctx_new (); 591 | impl->mZmqSocketSubscriber = zmq_socket (impl->mZmqContext, ZMQ_SUB); 592 | impl->mZmqSocketPublisher = zmq_socket (impl->mZmqContext, ZMQ_PUB); 593 | 594 | ZMQ_SET_SOCKET_OPTIONS (int,impl,SNDHWM,atoi); 595 | ZMQ_SET_SOCKET_OPTIONS (int,impl,RCVHWM,atoi); 596 | ZMQ_SET_SOCKET_OPTIONS (int,impl,SNDBUF,atoi); 597 | ZMQ_SET_SOCKET_OPTIONS (int,impl,RCVBUF,atoi); 598 | ZMQ_SET_SOCKET_OPTIONS (int,impl,RECONNECT_IVL,atoi); 599 | ZMQ_SET_SOCKET_OPTIONS (int,impl,RECONNECT_IVL_MAX,atoi); 600 | ZMQ_SET_SOCKET_OPTIONS (int,impl,BACKLOG,atoi); 601 | ZMQ_SET_SOCKET_OPTIONS (int,impl,RCVTIMEO,atoi); 602 | ZMQ_SET_SOCKET_OPTIONS (int,impl,SNDTIMEO,atoi); 603 | ZMQ_SET_SOCKET_OPTIONS (int,impl,RATE,atoi); 604 | ZMQ_SET_SOCKET_OPTIONS (uint64_t,impl,AFFINITY,atoll); 605 | ZMQ_SET_SOCKET_OPTIONS (const char*,impl,IDENTITY,); 606 | ZMQ_SET_SOCKET_OPTIONS (int64_t,impl,MAXMSGSIZE,atoll); 607 | 608 | for (i = 0; i < ZMQ_MAX_INCOMING_URIS; i++) 609 | { 610 | if (NULL == impl->mOutgoingAddress[i]) 611 | { 612 | break; 613 | } 614 | if (0 != zmqBridgeMamaTransportImpl_setupSocket (impl->mZmqSocketPublisher, 615 | impl->mOutgoingAddress[i], 616 | ZMQ_TPORT_DIRECTION_OUTGOING)) 617 | { 618 | return MAMA_STATUS_PLATFORM; 619 | } 620 | else 621 | { 622 | mama_log (MAMA_LOG_LEVEL_FINE, 623 | "zmqBridgeMamaTransportImpl_start(): Successfully set up " 624 | "outgoing ZeroMQ socket for URI: %s", 625 | impl->mOutgoingAddress[i]); 626 | } 627 | } 628 | 629 | for (i = 0; i < ZMQ_MAX_OUTGOING_URIS; i++) 630 | { 631 | if (NULL == impl->mIncomingAddress[i]) 632 | { 633 | break; 634 | } 635 | if (0 != zmqBridgeMamaTransportImpl_setupSocket (impl->mZmqSocketSubscriber, 636 | impl->mIncomingAddress[i], 637 | ZMQ_TPORT_DIRECTION_INCOMING)) 638 | { 639 | return MAMA_STATUS_PLATFORM; 640 | } 641 | else 642 | { 643 | mama_log (MAMA_LOG_LEVEL_FINE, 644 | "zmqBridgeMamaTransportImpl_start(): Successfully set up " 645 | "incoming ZeroMQ socket for URI: %s", 646 | impl->mIncomingAddress[i]); 647 | } 648 | } 649 | 650 | /* Set the transport bridge mIsDispatching to true. */ 651 | impl->mIsDispatching = 1; 652 | 653 | /* Initialize dispatch thread */ 654 | rc = wthread_create (&(impl->mOmzmqDispatchThread), 655 | NULL, 656 | zmqBridgeMamaTransportImpl_dispatchThread, 657 | impl); 658 | if (0 != rc) 659 | { 660 | mama_log (MAMA_LOG_LEVEL_ERROR, "zmqBridgeMamaTransportImpl_start(): " 661 | "wthread_create returned %d", rc); 662 | return MAMA_STATUS_PLATFORM; 663 | } 664 | return MAMA_STATUS_OK; 665 | } 666 | 667 | mama_status zmqBridgeMamaTransportImpl_stop (zmqTransportBridge* impl) 668 | { 669 | /* There are two mechanisms by which we can stop the transport 670 | * - Send a special message, which will be picked up by recv 671 | * For the instance when there is very little data flowing. 672 | * - Set the mIsDispatching variable in the transportBridge object to 673 | * false, for instances when there is a lot of data flowing. 674 | */ 675 | mama_status status = MAMA_STATUS_OK; 676 | 677 | /* Set the transportBridge mIsDispatching to false */ 678 | impl->mIsDispatching = 0; 679 | 680 | mama_log (MAMA_LOG_LEVEL_FINEST, "zmqBridgeMamaTransportImpl_stop(): " 681 | "Waiting on dispatch thread to terminate."); 682 | 683 | wthread_join (impl->mOmzmqDispatchThread, NULL); 684 | status = impl->mOmzmqDispatchStatus; 685 | 686 | mama_log (MAMA_LOG_LEVEL_FINEST, "zmqBridgeMamaTransportImpl_stop(): " 687 | "Rejoined with status: %s.", 688 | mamaStatus_stringForStatus(status)); 689 | 690 | return MAMA_STATUS_OK; 691 | } 692 | 693 | /** 694 | * Called when message removed from queue by dispatch thread 695 | * 696 | * @param data The AMQP payload 697 | * @param closure The subscriber 698 | */ 699 | void MAMACALLTYPE 700 | zmqBridgeMamaTransportImpl_queueCallback (mamaQueue queue, void* closure) 701 | { 702 | 703 | mama_status status = MAMA_STATUS_OK; 704 | mamaMsg tmpMsg = NULL; 705 | msgBridge bridgeMsg = NULL; 706 | memoryPool* pool = NULL; 707 | memoryNode* node = (memoryNode*) closure; 708 | zmqTransportMsg* tmsg = (zmqTransportMsg*) node->mNodeBuffer; 709 | uint32_t bufferSize = (uint32_t)tmsg->mNodeSize; 710 | const void* buffer = tmsg->mNodeBuffer; 711 | const char* subject = (char*)buffer; 712 | zmqSubscription* subscription = (zmqSubscription*) tmsg->mSubscription; 713 | zmqTransportBridge* impl = subscription->mTransport; 714 | zmqQueueBridge* queueImpl = NULL; 715 | 716 | /* Can't do anything without a subscriber */ 717 | if (NULL == subscription) 718 | { 719 | mama_log (MAMA_LOG_LEVEL_ERROR, 720 | "zmqBridgeMamaTransportImpl_queueCallback(): " 721 | "Called with NULL subscriber (destroyed?)"); 722 | return; 723 | } 724 | 725 | if (0 == endpointPool_isRegistedByContent (impl->mSubEndpoints, 726 | subject, 727 | subscription)) 728 | { 729 | mama_log (MAMA_LOG_LEVEL_ERROR, 730 | "zmqBridgeMamaTransportImpl_queueCallback(): " 731 | "Subscriber has been unregistered since msg was enqueued."); 732 | return; 733 | } 734 | 735 | /* Make sure that the subscription is processing messages */ 736 | if (1 != subscription->mIsNotMuted) 737 | { 738 | mama_log (MAMA_LOG_LEVEL_ERROR, 739 | "zmqBridgeMamaTransportImpl_queueCallback(): " 740 | "Skipping update - subscription %p is muted.", subscription); 741 | return; 742 | } 743 | 744 | /* This is the reuseable message stored on the associated MamaQueue */ 745 | tmpMsg = mamaQueueImpl_getMsg (subscription->mMamaQueue); 746 | if (NULL == tmpMsg) 747 | { 748 | mama_log (MAMA_LOG_LEVEL_ERROR, 749 | "zmqBridgeMamaTransportImpl_queueCallback(): " 750 | "Could not get cached mamaMsg from event queue."); 751 | return; 752 | } 753 | 754 | /* Get the bridge message from the mamaMsg */ 755 | status = mamaMsgImpl_getBridgeMsg (tmpMsg, &bridgeMsg); 756 | if (MAMA_STATUS_OK != status) 757 | { 758 | mama_log (MAMA_LOG_LEVEL_ERROR, 759 | "zmqBridgeMamaTransportImpl_queueCallback(): " 760 | "Could not get bridge message from cached " 761 | "queue mamaMsg [%s]", mamaStatus_stringForStatus (status)); 762 | return; 763 | } 764 | 765 | /* Unpack this bridge message into a MAMA msg implementation */ 766 | status = zmqBridgeMamaMsgImpl_deserialize (bridgeMsg, buffer, bufferSize, tmpMsg); 767 | if (MAMA_STATUS_OK != status) 768 | { 769 | mama_log (MAMA_LOG_LEVEL_ERROR, 770 | "zmqBridgeMamaTransportImpl_queueCallback(): " 771 | "zmqBridgeMamaMsgImpl_unpack() failed. [%s]", 772 | mamaStatus_stringForStatus (status)); 773 | } 774 | else 775 | { 776 | /* Process the message as normal */ 777 | status = mamaSubscription_processMsg (subscription->mMamaSubscription, 778 | tmpMsg); 779 | if (MAMA_STATUS_OK != status) 780 | { 781 | mama_log (MAMA_LOG_LEVEL_ERROR, 782 | "zmqBridgeMamaTransportImpl_queueCallback(): " 783 | "mamaSubscription_processMsg() failed. [%d]", status); 784 | } 785 | } 786 | 787 | mamaQueue_getNativeHandle (queue, (void**)&queueImpl); 788 | 789 | // Return the memory node to the pool 790 | pool = (memoryPool*) baseBridgeMamaQueueImpl_getClosure ((queueBridge) queueImpl); 791 | memoryPool_returnNode (pool, node); 792 | 793 | return; 794 | } 795 | 796 | const char* zmqBridgeMamaTransportImpl_getParameterWithVaList ( 797 | char* defaultVal, 798 | char* paramName, 799 | const char* format, 800 | va_list arguments) 801 | { 802 | const char* property = NULL; 803 | 804 | /* Create the complete transport property string */ 805 | vsnprintf (paramName, PARAM_NAME_MAX_LENGTH, 806 | format, arguments); 807 | 808 | /* Get the property out for analysis */ 809 | property = properties_Get (mamaInternal_getProperties (), 810 | paramName); 811 | /* Properties will return NULL if parameter is not specified in configs */ 812 | if (property == NULL) 813 | { 814 | property = defaultVal; 815 | } 816 | 817 | return property; 818 | } 819 | 820 | const char* zmqBridgeMamaTransportImpl_getParameter ( 821 | const char* defaultVal, 822 | const char* format, ...) 823 | { 824 | char paramName[PARAM_NAME_MAX_LENGTH]; 825 | const char* returnVal = NULL; 826 | /* Create list for storing the parameters passed in */ 827 | va_list arguments; 828 | 829 | /* Populate list with arguments passed in */ 830 | va_start (arguments, format); 831 | 832 | returnVal = zmqBridgeMamaTransportImpl_getParameterWithVaList ( 833 | (char*)defaultVal, 834 | paramName, 835 | format, 836 | arguments); 837 | 838 | /* These will be equal if unchanged */ 839 | if (returnVal == defaultVal) 840 | { 841 | mama_log (MAMA_LOG_LEVEL_FINER, 842 | "zmqBridgeMamaTransportImpl_getParameter: " 843 | "parameter [%s]: [%s] (Default)", 844 | paramName, 845 | returnVal); 846 | } 847 | else 848 | { 849 | mama_log (MAMA_LOG_LEVEL_FINER, 850 | "zmqBridgeMamaTransportImpl_getParameter: " 851 | "parameter [%s]: [%s] (User Defined)", 852 | paramName, 853 | returnVal); 854 | } 855 | 856 | /* Clean up the list */ 857 | va_end(arguments); 858 | 859 | return returnVal; 860 | } 861 | 862 | void* zmqBridgeMamaTransportImpl_dispatchThread (void* closure) 863 | { 864 | zmqTransportBridge* impl = (zmqTransportBridge*)closure; 865 | const char* subject = NULL; 866 | endpoint_t* subs = NULL; 867 | size_t subCount = 0; 868 | size_t subInc = 0; 869 | mama_status status = MAMA_STATUS_OK; 870 | zmqSubscription* subscription = NULL; 871 | 872 | /* 873 | * Check if we should be still dispatching. 874 | * We shouldn't need to lock around this, as we're performing a simple value 875 | * read - if it changes in the middle of the read, we don't actually care. 876 | */ 877 | zmq_msg_t zmsg; 878 | zmq_msg_init (&zmsg); 879 | while (1 == impl->mIsDispatching) 880 | { 881 | int size = -1; 882 | size = zmq_msg_recv(&zmsg, impl->mZmqSocketSubscriber, 0); 883 | if (size == -1) 884 | { 885 | continue; 886 | } 887 | 888 | // We just received a message if we got this far 889 | subject = (char*) zmq_msg_data (&zmsg); 890 | 891 | status = endpointPool_getRegistered (impl->mSubEndpoints, 892 | subject, 893 | &subs, 894 | &subCount); 895 | 896 | if (MAMA_STATUS_OK != status) 897 | { 898 | mama_log (MAMA_LOG_LEVEL_ERROR, 899 | "zmqBridgeMamaTransportImpl_dispatchThread(): " 900 | "Could not query registration table " 901 | "for symbol %s (%s)", 902 | subject, 903 | mamaStatus_stringForStatus (status)); 904 | 905 | continue; 906 | } 907 | 908 | if (0 == subCount) 909 | { 910 | mama_log (MAMA_LOG_LEVEL_FINEST, 911 | "zmqBridgeMamaTransportImpl_dispatchThread(): " 912 | "discarding uninteresting message " 913 | "for symbol %s", subject); 914 | 915 | continue; 916 | } 917 | 918 | for (subInc = 0; subInc < subCount; subInc++) 919 | { 920 | queueBridge queueImpl = NULL; 921 | memoryPool* pool = NULL; 922 | memoryNode* node = NULL; 923 | zmqTransportMsg* tmsg = NULL; 924 | 925 | subscription = (zmqSubscription*)subs[subInc]; 926 | if (1 == subscription->mIsTportDisconnected) 927 | { 928 | subscription->mIsTportDisconnected = 0; 929 | } 930 | 931 | if (1 != subscription->mIsNotMuted) 932 | { 933 | mama_log (MAMA_LOG_LEVEL_FINEST, 934 | "zmqBridgeMamaTransportImpl_dispatchThread(): " 935 | "muted - not queueing update for symbol %s", 936 | subject); 937 | continue; 938 | } 939 | 940 | queueImpl = (queueBridge) subscription->mZmqQueue; 941 | 942 | /* Get the memory pool from the queue, creating if necessary */ 943 | pool = (memoryPool*) baseBridgeMamaQueueImpl_getClosure (queueImpl); 944 | if (NULL == pool) 945 | { 946 | pool = memoryPool_create (impl->mMemoryPoolSize, impl->mMemoryNodeSize); 947 | baseBridgeMamaQueueImpl_setClosure (queueImpl, pool, 948 | zmqBridgeMamaTransportImpl_queueClosureCleanupCb); 949 | } 950 | 951 | // allocate/populate zmqTransportMsg 952 | node = memoryPool_getNode (pool, sizeof(zmqTransportMsg) + zmq_msg_size(&zmsg)); 953 | tmsg = (zmqTransportMsg*) node->mNodeBuffer; 954 | tmsg->mNodeBuffer = (uint8_t*)(tmsg + 1); 955 | tmsg->mNodeSize = zmq_msg_size(&zmsg); 956 | tmsg->mSubscription = subscription; 957 | memcpy (tmsg->mNodeBuffer, zmq_msg_data(&zmsg),tmsg->mNodeSize); 958 | 959 | // callback (queued) will release the message 960 | baseBridgeMamaQueue_enqueueEvent ((queueBridge) queueImpl, 961 | zmqBridgeMamaTransportImpl_queueCallback, node); 962 | } 963 | } 964 | 965 | impl->mOmzmqDispatchStatus = MAMA_STATUS_OK; 966 | return NULL; 967 | } 968 | 969 | void MAMACALLTYPE 970 | zmqBridgeMamaTransportImpl_queueClosureCleanupCb (void* closure) 971 | { 972 | memoryPool* pool = (memoryPool*) closure; 973 | if (NULL != pool) 974 | { 975 | mama_log (MAMA_LOG_LEVEL_FINE, 976 | "Destroying memory pool for queue %p.", closure); 977 | memoryPool_destroy (pool, NULL); 978 | } 979 | } 980 | --------------------------------------------------------------------------------