diff options
-rw-r--r-- | extras/dispatch/CMakeLists.txt | 16 | ||||
-rw-r--r-- | extras/dispatch/include/qpid/dispatch/config.h | 29 | ||||
-rw-r--r-- | extras/dispatch/include/qpid/dispatch/dispatch.h | 8 | ||||
-rw-r--r-- | extras/dispatch/router/src/main.c | 2 | ||||
-rw-r--r-- | extras/dispatch/src/config.c | 203 | ||||
-rw-r--r-- | extras/dispatch/src/config_private.h | 29 | ||||
-rw-r--r-- | extras/dispatch/src/dispatch.c | 39 | ||||
-rw-r--r-- | extras/dispatch/src/py/config/__init__.py | 20 | ||||
-rw-r--r-- | extras/dispatch/src/py/config/configparse.py | 146 | ||||
-rw-r--r-- | extras/dispatch/src/python_embedded.c | 64 | ||||
-rw-r--r-- | extras/dispatch/src/python_embedded.h | 29 | ||||
-rw-r--r-- | extras/dispatch/src/router_node.c | 2 | ||||
-rw-r--r-- | extras/dispatch/src/server.c | 3 |
13 files changed, 577 insertions, 13 deletions
diff --git a/extras/dispatch/CMakeLists.txt b/extras/dispatch/CMakeLists.txt index f96f62817b..d01e6c1321 100644 --- a/extras/dispatch/CMakeLists.txt +++ b/extras/dispatch/CMakeLists.txt @@ -17,15 +17,22 @@ ## under the License. ## +project(qpid-dispatch C) + cmake_minimum_required(VERSION 2.6) include(CheckLibraryExists) include(CheckSymbolExists) - -project(qpid-dispatch C) +include(CheckFunctionExists) +include(CheckIncludeFiles) +include(FindPythonLibs) enable_testing() include (CTest) +if (NOT PYTHONLIBS_FOUND) + message(FATAL_ERROR "Python Development Libraries are needed.") +endif (NOT PYTHONLIBS_FOUND) + set (SO_VERSION_MAJOR 0) set (SO_VERSION_MINOR 1) set (SO_VERSION "${SO_VERSION_MAJOR}.${SO_VERSION_MINOR}") @@ -49,6 +56,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src ${proton_include} + ${PYTHON_INCLUDE_DIRS} ) ## @@ -70,6 +78,7 @@ set(server_SOURCES src/alloc.c src/auth.c src/buffer.c + src/config.c src/container.c src/dispatch.c src/hash.c @@ -78,6 +87,7 @@ set(server_SOURCES src/log.c src/message.c src/posix/threading.c + src/python_embedded.c src/router_node.c src/server.c src/timer.c @@ -85,7 +95,7 @@ set(server_SOURCES ) add_library(qpid-dispatch SHARED ${server_SOURCES}) -target_link_libraries(qpid-dispatch ${proton_lib} ${pthread_lib} ${rt_lib}) +target_link_libraries(qpid-dispatch ${proton_lib} ${pthread_lib} ${rt_lib} ${PYTHON_LIBRARIES}) set_target_properties(qpid-dispatch PROPERTIES VERSION "${SO_VERSION}" SOVERSION "${SO_VERSION_MAJOR}" diff --git a/extras/dispatch/include/qpid/dispatch/config.h b/extras/dispatch/include/qpid/dispatch/config.h new file mode 100644 index 0000000000..81f7bc5d98 --- /dev/null +++ b/extras/dispatch/include/qpid/dispatch/config.h @@ -0,0 +1,29 @@ +#ifndef __dispatch_config_h__ +#define __dispatch_config_h__ 1 +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +typedef struct dx_config_t dx_config_t; + +int dx_config_item_count(const dx_config_t *config, const char *section); +const char *dx_config_item_value_string(const dx_config_t *config, const char *section, int index, const char* key); +uint32_t dx_config_item_value_int(const dx_config_t *config, const char *section, int index, const char* key); + +#endif diff --git a/extras/dispatch/include/qpid/dispatch/dispatch.h b/extras/dispatch/include/qpid/dispatch/dispatch.h index d6c2832f6f..e785cb6385 100644 --- a/extras/dispatch/include/qpid/dispatch/dispatch.h +++ b/extras/dispatch/include/qpid/dispatch/dispatch.h @@ -29,15 +29,9 @@ typedef struct dx_dispatch_t dx_dispatch_t; /** * \brief Initialize the Dispatch library and prepare it for operation. * - * @param thread_count The number of worker threads (1 or more) that the server shall create - * @param container_name The name of the container. If NULL, a UUID will be generated. - * @param router_area The name of the router's area. If NULL, a default value will be supplied. - * @param router_id The identifying name of the router. If NULL, it will be set the same as the - * container_name. * @return A handle to be used in API calls for this instance. */ -dx_dispatch_t *dx_dispatch(int thread_count, const char *container_name, - const char *router_area, const char *router_id); +dx_dispatch_t *dx_dispatch(); /** diff --git a/extras/dispatch/router/src/main.c b/extras/dispatch/router/src/main.c index 5fb194980b..d97895208f 100644 --- a/extras/dispatch/router/src/main.c +++ b/extras/dispatch/router/src/main.c @@ -106,7 +106,7 @@ int main(int argc, char **argv) { dx_log_set_mask(LOG_INFO | LOG_TRACE | LOG_ERROR); - dispatch = dx_dispatch(4, "Qpid.Dispatch", "area", "Router.A"); + dispatch = dx_dispatch(); dx_server_set_signal_handler(dispatch, server_signal_handler, 0); dx_server_set_start_handler(dispatch, thread_start_handler, 0); diff --git a/extras/dispatch/src/config.c b/extras/dispatch/src/config.c new file mode 100644 index 0000000000..bc99d7f91c --- /dev/null +++ b/extras/dispatch/src/config.c @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "python_embedded.h" +#include "config_private.h" +#include <qpid/dispatch/alloc.h> +#include <qpid/dispatch/log.h> + +#define PYTHON_MODULE "config" + +static const char *log_module = "CONFIG"; + +struct dx_config_t { + PyObject *pModule; + PyObject *pClass; + PyObject *pObject; +}; + +ALLOC_DECLARE(dx_config_t); +ALLOC_DEFINE(dx_config_t); + +void dx_config_initialize() +{ + dx_python_start(); +} + + +void dx_config_finalize() +{ + dx_python_stop(); +} + + +dx_config_t *dx_config(char *filename) +{ + dx_config_t *config = new_dx_config_t(); + + // + // Load the Python configuration module and get a reference to the config class. + // + PyObject *pName = PyString_FromString(PYTHON_MODULE); + config->pModule = PyImport_Import(pName); + Py_DECREF(pName); + + if (!config->pModule) { + PyErr_Print(); + free_dx_config_t(config); + dx_log(log_module, LOG_ERROR, "Unable to load configuration module: %s", PYTHON_MODULE); + return 0; + } + + config->pClass = PyObject_GetAttrString(config->pModule, "DXConfig"); + if (!config->pClass || !PyClass_Check(config->pClass)) { + PyErr_Print(); + Py_DECREF(config->pModule); + free_dx_config_t(config); + dx_log(log_module, LOG_ERROR, "Problem with configuration module: Missing DXConfig class"); + return 0; + } + + // + // Instantiate the DXConfig class, passing in the configuration file name. + // + PyObject *pArgs = PyTuple_New(1); + PyObject *fname = PyString_FromString(filename); + PyTuple_SetItem(pArgs, 0, fname); + config->pObject = PyInstance_New(config->pClass, pArgs, 0); + Py_DECREF(pArgs); + + if (config->pObject == 0) { + PyErr_Print(); + Py_DECREF(config->pModule); + free_dx_config_t(config); + dx_log(log_module, LOG_ERROR, "Configuration file '%s' could not be read", filename); + return 0; + } + + return config; +} + + +void dx_config_free(dx_config_t *config) +{ + if (config) { + Py_DECREF(config->pClass); + Py_DECREF(config->pModule); + free_dx_config_t(config); + } +} + + +int dx_config_item_count(const dx_config_t *config, const char *section) +{ + PyObject *pSection; + PyObject *pMethod; + PyObject *pArgs; + PyObject *pResult; + int result = 0; + + pMethod = PyObject_GetAttrString(config->pObject, "item_count"); + if (!pMethod || !PyCallable_Check(pMethod)) { + dx_log(log_module, LOG_ERROR, "Problem with configuration module: No callable 'item_count'"); + if (pMethod) + Py_DECREF(pMethod); + return 0; + } + + pSection = PyString_FromString(section); + pArgs = PyTuple_New(1); + PyTuple_SetItem(pArgs, 0, pSection); + pResult = PyObject_CallObject(pMethod, pArgs); + Py_DECREF(pArgs); + if (pResult && PyInt_Check(pResult)) + result = (int) PyInt_AsLong(pResult); + if (pResult) + Py_DECREF(pResult); + Py_DECREF(pMethod); + + return result; +} + + +static PyObject *item_value(const dx_config_t *config, const char *section, int index, const char* key, const char* method) +{ + PyObject *pSection; + PyObject *pIndex; + PyObject *pKey; + PyObject *pMethod; + PyObject *pArgs; + PyObject *pResult; + + pMethod = PyObject_GetAttrString(config->pObject, method); + if (!pMethod || !PyCallable_Check(pMethod)) { + dx_log(log_module, LOG_ERROR, "Problem with configuration module: No callable '%s'", method); + if (pMethod) + Py_DECREF(pMethod); + return 0; + } + + pSection = PyString_FromString(section); + pIndex = PyInt_FromLong((long) index); + pKey = PyString_FromString(key); + pArgs = PyTuple_New(3); + PyTuple_SetItem(pArgs, 0, pSection); + PyTuple_SetItem(pArgs, 1, pIndex); + PyTuple_SetItem(pArgs, 2, pKey); + pResult = PyObject_CallObject(pMethod, pArgs); + Py_DECREF(pArgs); + Py_DECREF(pMethod); + + return pResult; +} + + +const char *dx_config_item_value_string(const dx_config_t *config, const char *section, int index, const char* key) +{ + PyObject *pResult = item_value(config, section, index, key, "value_string"); + char *value = 0; + + if (pResult && PyString_Check(pResult)) { + Py_ssize_t size = PyString_Size(pResult); + value = (char*) malloc(size + 1); + strncpy(value, PyString_AsString(pResult), size + 1); + } + + if (pResult) + Py_DECREF(pResult); + + return value; +} + + +uint32_t dx_config_item_value_int(const dx_config_t *config, const char *section, int index, const char* key) +{ + PyObject *pResult = item_value(config, section, index, key, "value_int"); + uint32_t value = 0; + + if (pResult && PyLong_Check(pResult)) + value = (uint32_t) PyLong_AsLong(pResult); + + if (pResult) + Py_DECREF(pResult); + + return value; +} + + diff --git a/extras/dispatch/src/config_private.h b/extras/dispatch/src/config_private.h new file mode 100644 index 0000000000..bb114ebde0 --- /dev/null +++ b/extras/dispatch/src/config_private.h @@ -0,0 +1,29 @@ +#ifndef __config_private_h__ +#define __config_private_h__ 1 +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <qpid/dispatch/config.h> + +void dx_config_initialize(); +void dx_config_finalize(); +dx_config_t *dx_config(char *filename); +void dx_config_free(dx_config_t *config); + +#endif diff --git a/extras/dispatch/src/dispatch.c b/extras/dispatch/src/dispatch.c index 0176d3189e..3c8fa9ba83 100644 --- a/extras/dispatch/src/dispatch.c +++ b/extras/dispatch/src/dispatch.c @@ -17,10 +17,12 @@ * under the License. */ +#include "python_embedded.h" #include <qpid/dispatch.h> #include "dispatch_private.h" #include "alloc_private.h" #include "log_private.h" +#include "config_private.h" /** * Private Function Prototypes @@ -38,14 +40,43 @@ dx_agent_t *dx_agent(dx_dispatch_t *dx); void dx_agent_free(dx_agent_t *agent); -dx_dispatch_t *dx_dispatch(int thread_count, const char *container_name, - const char *router_area, const char *router_id) +static const char *CONF_CONTAINER = "container"; +static const char *CONF_ROUTER = "router"; + + +dx_dispatch_t *dx_dispatch() { dx_dispatch_t *dx = NEW(dx_dispatch_t); + int thread_count = 0; + const char *container_name = 0; + const char *router_area = 0; + const char *router_id = 0; + + dx_python_initialize(); dx_log_initialize(); dx_alloc_initialize(); + dx_config_initialize(); + dx_config_t *config = dx_config("../etc/qpid-dispatch.conf"); + + if (config) { + int count = dx_config_item_count(config, CONF_CONTAINER); + if (count == 1) { + thread_count = dx_config_item_value_int(config, CONF_CONTAINER, 0, "worker-threads"); + container_name = dx_config_item_value_string(config, CONF_CONTAINER, 0, "container-name"); + } + + count = dx_config_item_count(config, CONF_ROUTER); + if (count == 1) { + router_area = dx_config_item_value_string(config, CONF_ROUTER, 0, "area"); + router_id = dx_config_item_value_string(config, CONF_ROUTER, 0, "router-id"); + } + } + + if (thread_count == 0) + thread_count = 1; + if (!container_name) container_name = "00000000-0000-0000-0000-000000000000"; // TODO - gen a real uuid @@ -64,16 +95,20 @@ dx_dispatch_t *dx_dispatch(int thread_count, const char *container_name, dx_container_setup_agent(dx); dx_router_setup_agent(dx); + dx_config_free(config); + return dx; } void dx_dispatch_free(dx_dispatch_t *dx) { + dx_config_finalize(); dx_agent_free(dx->agent); dx_router_free(dx->router); dx_container_free(dx->container); dx_server_free(dx->server); dx_log_finalize(); + dx_python_finalize(); } diff --git a/extras/dispatch/src/py/config/__init__.py b/extras/dispatch/src/py/config/__init__.py new file mode 100644 index 0000000000..349026251a --- /dev/null +++ b/extras/dispatch/src/py/config/__init__.py @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from config.configparse import DXConfig diff --git a/extras/dispatch/src/py/config/configparse.py b/extras/dispatch/src/py/config/configparse.py new file mode 100644 index 0000000000..051c3d3187 --- /dev/null +++ b/extras/dispatch/src/py/config/configparse.py @@ -0,0 +1,146 @@ +## +## Licensed to the Apache Software Foundation (ASF) under one +## or more contributor license agreements. See the NOTICE file +## distributed with this work for additional information +## regarding copyright ownership. The ASF licenses this file +## to you under the Apache License, Version 2.0 (the +## "License"); you may not use this file except in compliance +## with the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, +## software distributed under the License is distributed on an +## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +## KIND, either express or implied. See the License for the +## specific language governing permissions and limitations +## under the License +## + +import json + +class DXConfig: + """ + Configuration File Parser for Qpid Dispatch + + Configuration files are made up of "sections" having the following form: + + section-name { + key0: value0 + key1: value1 + ... + keyN: valueN + } + + Sections may be repeated (i.e. there may be multiple instances with the same section name). + The keys must be unique within a section. Values can be of string or integer types. No + quoting is necessary anywhere in the configuration file. Values may contain whitespace. + + Comment lines starting with the '#' character will be ignored. + + This parser converts the configuration file into a json string where the file is represented + as a list of maps. Each map has one item, the key being the section name and the value being + a nested map of keys and values from the file. This json string is parsed into a data + structure that may then be queried. + + """ + + def __init__(self, path): + self.path = path + self.config = None + + cfile = open(self.path) + text = cfile.read() + cfile.close() + + self.json_text = "[" + self._toJson(text) + "]" + self.config = json.loads(self.json_text); + + + def __repr__(self): + return "%r" % self.config + + + def _toJson(self, text): + lines = text.split('\n') + stripped = "" + for line in lines: + sline = line.strip() + + # + # Ignore empty lines + # + if len(sline) == 0: + continue + + # + # Ignore comment lines + # + if sline.find('#') == 0: + continue + + # + # Convert section opens, closes, and colon-separated key:value lines into json + # + if sline[-1:] == '{': + sline = '{"' + sline[:-1].strip() + '" : {' + elif sline == '}': + sline = '}},' + else: + colon = sline.find(':') + if colon > 1: + sline = '"' + sline[:colon] + '":"' + sline[colon+1:].strip() + '",' + stripped += sline + + # + # Remove the trailing commas in map entries + # + stripped = stripped.replace(",}", "}") + + # + # Return the entire document minus the trailing comma + # + return stripped[:-1] + + + def _getSection(self, section): + result = [] + for item in self.config: + if item.__class__ == dict and section in item: + result.append(item[section]) + return result + + + def item_count(self, section): + """ + Return the number of items in a section (i.e. the number if instances of a section-name). + """ + sec = self._getSection(section) + return len(sec) + + def _value(self, section, idx, key): + sec = self._getSection(section) + if idx >= len(sec): + return None + item = sec[idx] + if item.__class__ == dict and key in item: + return item[key] + return None + + def value_string(self, section, idx, key): + """ + Return the string value for the key in the idx'th item in the section. + """ + value = self._value(section, idx, key) + if value: + return str(value) + return None + + def value_int(self, section, idx, key): + """ + Return the integer value for the key in the idx'th item in the section. + """ + value = self._value(section, idx, key) + return long(value) + + diff --git a/extras/dispatch/src/python_embedded.c b/extras/dispatch/src/python_embedded.c new file mode 100644 index 0000000000..17c97ae10e --- /dev/null +++ b/extras/dispatch/src/python_embedded.c @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "python_embedded.h" +#include <qpid/dispatch/threading.h> +#include <qpid/dispatch/log.h> + +static uint32_t ref_count = 0; +static sys_mutex_t *lock = 0; +static char *log_module = "PYTHON"; + +void dx_python_initialize() +{ + lock = sys_mutex(); +} + + +void dx_python_finalize() +{ + assert(ref_count == 0); + sys_mutex_free(lock); +} + + +void dx_python_start() +{ + sys_mutex_lock(lock); + if (ref_count == 0) { + Py_Initialize(); + dx_log(log_module, LOG_TRACE, "Embedded Python Interpreter Initialized"); + } + ref_count++; + sys_mutex_unlock(lock); +} + + +void dx_python_stop() +{ + sys_mutex_lock(lock); + ref_count--; + if (ref_count == 0) { + Py_Finalize(); + dx_log(log_module, LOG_TRACE, "Embedded Python Interpreter Shut Down"); + } + sys_mutex_unlock(lock); +} + + diff --git a/extras/dispatch/src/python_embedded.h b/extras/dispatch/src/python_embedded.h new file mode 100644 index 0000000000..455925eecf --- /dev/null +++ b/extras/dispatch/src/python_embedded.h @@ -0,0 +1,29 @@ +#ifndef __python_embedded_h__ +#define __python_embedded_h__ 1 +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <Python.h> + +void dx_python_initialize(); +void dx_python_finalize(); +void dx_python_start(); +void dx_python_stop(); + +#endif diff --git a/extras/dispatch/src/router_node.c b/extras/dispatch/src/router_node.c index e361e9ce8e..bfa89eddf4 100644 --- a/extras/dispatch/src/router_node.c +++ b/extras/dispatch/src/router_node.c @@ -509,6 +509,8 @@ dx_router_t *dx_router(dx_dispatch_t *dx, const char *area, const char *id) // dx_field_iterator_set_address(area, id); + dx_log(module, LOG_INFO, "Router started, area=%s id=%s", area, id); + return router; } diff --git a/extras/dispatch/src/server.c b/extras/dispatch/src/server.c index fccee7fac0..41df72e1b5 100644 --- a/extras/dispatch/src/server.c +++ b/extras/dispatch/src/server.c @@ -605,6 +605,8 @@ dx_server_t *dx_server(int thread_count, const char *container_name) dx_server->pause_now_serving = 0; dx_server->pending_signal = 0; + dx_log(module, LOG_INFO, "Container Name: %s", dx_server->container_name); + return dx_server; } @@ -727,6 +729,7 @@ void dx_server_signal(dx_dispatch_t *dx, int signum) dx_server->pending_signal = signum; sys_cond_signal_all(dx_server->cond); + pn_driver_wakeup(dx_server->driver); } |